diff --git a/.gitignore b/.gitignore index 68b4f668..7c61ca6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,15 @@ - -/Console2.ncb -/Console2.suo bin/ obj/ +ipch/ help/console.chm *.aps *.user +*.opensdf +*.sdf +*.suo + +*~ +*.bak +*.orig +*.swp 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/Console/AboutDlg.cpp b/Console/AboutDlg.cpp index 1d3e6968..8ae40ba2 100644 --- a/Console/AboutDlg.cpp +++ b/Console/AboutDlg.cpp @@ -9,13 +9,18 @@ LRESULT CAboutDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - CWindow staticMessage(GetDlgItem(IDC_STATIC_VERSION)); - CString strMsg; - - strMsg.Format(L"Console %i.%02i.%i", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); - staticMessage.SetWindowText(strMsg); +#ifdef _USE_AERO + AERO_CONTROL(CButton, m_Ok, IDOK) + this->OpenThemeData(VSCLASS_WINDOW); +#else + CString strMsg; + strMsg.Format(L"\nConsoleZ %i.%i.%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 c7276585..33a3ae88 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) @@ -22,4 +30,59 @@ class CAboutDlg : public CDialogImpl 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.%i.%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-2012\nChristophe Bucher\n\na modified version of\nConsole 2\nfrom\nMarko Bozikovic", + rectAppText, + DT_CENTER | DT_VCENTER, dtto); + } +#endif }; diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h new file mode 100644 index 00000000..10191233 --- /dev/null +++ b/Console/AeroTabCtrl.h @@ -0,0 +1,1062 @@ +#pragma once + +/* Aero default theme drawn an internal border (2 pixels) */ +#define AERO_FRAME_BORDER_SIZE 2; + +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; + signed long m_iCloseButtonWidth; + signed long m_iCloseButtonHeight; + + bool m_bAppActive; + + // Constructor +public: + + CAeroTabCtrlImpl():m_iTopMargin(0),m_bAppActive(true) + { + // 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); + } + + void SetTopMargin(int nTopMargin) + { + m_iTopMargin = static_cast(nTopMargin); + } + + void SetAppActiveStatus(bool bAppActive) + { + m_bAppActive = bAppActive; + } + + // 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_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; + } + +#if 0 + void ClearBackground(Gdiplus::Graphics& g, LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + if( this->m_bAeroGlassActive ) + { + BOOL fEnabled = FALSE; + DwmIsCompositionEnabled(&fEnabled); + if( !fEnabled ) + { + g.Clear(m_clrBackground); + } + else + { + g.Clear(Gdiplus::Color(0,0,0,0)); + } + } + else + { + g.Clear( + Gdiplus::Color( + Gdiplus::Color::MakeARGB( + 255, + GetRValue(lpNMCustomDraw->clrBtnFace), + GetGValue(lpNMCustomDraw->clrBtnFace), + GetBValue(lpNMCustomDraw->clrBtnFace)))); + } + } +#endif + + // Overrides for painting from CDotNetTabCtrlImpl +public: + + void DrawBackground(RECT /*rcClient*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + if( !aero::IsComposing() ) + { + Gdiplus::Graphics g(lpNMCustomDraw->nmcd.hdc); + COLORREF clr = lpNMCustomDraw->clrBtnFace; + + g.Clear( + Gdiplus::Color( + 255, + GetRValue(clr), + GetGValue(clr), + GetBValue(clr))); + } + } + + 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); + + 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); + +#ifdef _DRAW_TAB_RECT + { + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Green))); + g.DrawRectangle( + &pen, + X, Y, + width, height); + } +#endif //_DRAW_TAB_RECT + } + + 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); + +#ifdef _DRAW_TAB_RECT + { + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Green))); + g.DrawRectangle( + &pen, + X, Y - height, + width, height); + } +#endif //_DRAW_TAB_RECT + } + + void DrawItem_InitBounds(DWORD /*dwStyle*/, RECT /*rcItem*/, RECT& rcTab, RECT& rcText, int& nIconVerticalCenter) + { + DWORD dwStyle = this->GetStyle(); + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + { + rcText.top += AERO_FRAME_BORDER_SIZE; + rcTab.top += AERO_FRAME_BORDER_SIZE; + rcText.bottom -= m_iTopMargin; + rcText.left += (m_iLeftSpacing + m_iMargin); + rcText.right -= m_iMargin; + } + else + { + rcText.top += m_iTopMargin; + rcText.bottom -= AERO_FRAME_BORDER_SIZE; + rcTab.bottom -= AERO_FRAME_BORDER_SIZE; + rcText.left += (m_iLeftSpacing + m_iMargin); + rcText.right -= m_iMargin; + } + nIconVerticalCenter = (rcText.bottom + rcText.top) / 2; + + if (CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON)) + { + rcText.right -= m_iCloseButtonWidth; + } + } + + 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) + { + CBufferedPaint bufferedPaint; + HDC hDCPaint = NULL; + BP_PAINTPARAMS paintParams = { sizeof(BP_PAINTPARAMS), BPPF_ERASE, NULL, NULL }; + bufferedPaint.Begin(lpNMCustomDraw->nmcd.hdc, &rcTab, BPBF_TOPDOWNDIB, &paintParams, &hDCPaint); + CDCHandle dcPaint(hDCPaint); + + Gdiplus::Graphics g(dcPaint); + + 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( + dcPaint, + ( 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 CAeroTabCtrlImpl interprets padding, margin, etc.: + // + // M - Margin + // P - Padding + // I - Image + // C - Close button + // Text - Tab Text + // + // With image & With close button: + // | M | I | P | Text | P | C | M | + // + // Without image & With close Button : + // | M | P | Text | P | C | M | + // + // 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()) + { + // 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 tabSmallIcon(m_imageList.ExtractIcon(nImageIndex)); + if( !tabSmallIcon.IsNull() ) + { + dcPaint.DrawIconEx( + rcText.left, nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset, + tabSmallIcon.m_hIcon, + 16, 16); + } + +#ifdef _DRAW_TAB_RECT + { + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Cyan))); + g.DrawRectangle( + &pen, + rcText.left, nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset, + 15, 15); + } +#endif //_DRAW_TAB_RECT + } + + // 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); + if( hTheme ) + { + ::DrawThemeTextEx( + hTheme, + dcPaint, + WP_CAPTION, CS_ACTIVE, + szTitle, + szTitleLen, + DT_PATH_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX, + &rcText, + &dtto); + + ::CloseThemeData(hTheme); + } + else + { + dcPaint.SetBkMode(TRANSPARENT); + dcPaint.DrawText( + szTitle, + szTitleLen, + &rcText, + DT_PATH_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX); + } + } + +#ifdef _DRAW_TAB_RECT + { + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Yellow))); + g.DrawRectangle( + &pen, + rcTab.left, rcTab.top, + rcTab.right - rcTab.left - 1, rcTab.bottom - rcTab.top - 1); + } + + { + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Red))); + g.DrawRectangle( + &pen, + rcText.left, rcText.top, + rcText.right - rcText.left - 1, rcText.bottom - rcText.top - 1); + } +#endif //_DRAW_TAB_RECT + + bufferedPaint.End(); + } + + void DrawCloseButton(LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + // drawed in the current tab + + // we want to clip the close button without distorting/shrinking + CBufferedPaint bufferedPaint; + HDC hDCPaint = NULL; + BP_PAINTPARAMS paintParams = { sizeof(BP_PAINTPARAMS), BPPF_ERASE, NULL, NULL }; + bufferedPaint.Begin(lpNMCustomDraw->nmcd.hdc, &m_rcCloseButton, BPBF_TOPDOWNDIB, &paintParams, &hDCPaint); + CDCHandle dcPaint(hDCPaint); + + RECT rcCloseButton = m_rcCloseButton; + rcCloseButton.right = rcCloseButton.left + m_iCloseButtonWidth; + + 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); + if( hTheme ) + { + ::DrawThemeBackgroundEx( + hTheme, + dcPaint, + WP_SMALLCLOSEBUTTON, + iStateCloseButton, + &rcCloseButton, + NULL); + + ::CloseThemeData(hTheme); + } + else + { + Gdiplus::Graphics g(dcPaint); + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Red))); + g.DrawRectangle( + &pen, + rcCloseButton.left, rcCloseButton.top, + rcCloseButton.right - rcCloseButton.left, rcCloseButton.bottom - rcCloseButton.top); + g.DrawLine( + &pen, + rcCloseButton.left, rcCloseButton.top, + rcCloseButton.right, rcCloseButton.bottom); + g.DrawLine( + &pen, + rcCloseButton.right, rcCloseButton.top, + rcCloseButton.left, rcCloseButton.bottom); + } + +#ifdef _DRAW_TAB_RECT + { + Gdiplus::Graphics g(dcPaint); + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Cyan))); + g.DrawRectangle( + &pen, + rcCloseButton.left, rcCloseButton.top, + rcCloseButton.right - rcCloseButton.left, rcCloseButton.bottom - rcCloseButton.top); + } +#endif //_DRAW_TAB_RECT + + bufferedPaint.End(); + + } + + 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; + + 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 hTheme = ::OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); + if( hTheme ) + { + ::DrawThemeBackgroundEx( + hTheme, + lpNMCustomDraw->nmcd.hdc, + NAV_BACKBUTTON, + iStateScrollLeft, + &m_rcScrollLeft, + NULL); + + ::DrawThemeBackgroundEx( + hTheme, + lpNMCustomDraw->nmcd.hdc, + NAV_FORWARDBUTTON, + iStateScrollRight, + &m_rcScrollRight, + NULL); + + ::CloseThemeData(hTheme); + } + else + { + Gdiplus::Graphics g(lpNMCustomDraw->nmcd.hdc); + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Navy))); + int nHalfHeight = (m_rcScrollLeft.bottom - m_rcScrollLeft.top) >> 1; + g.DrawLine( + &pen, + m_rcScrollLeft.right, m_rcScrollLeft.top, + m_rcScrollLeft.right, m_rcScrollLeft.bottom); + g.DrawLine( + &pen, + m_rcScrollLeft.right, m_rcScrollLeft.top, + m_rcScrollLeft.left, m_rcScrollLeft.top + nHalfHeight); + g.DrawLine( + &pen, + m_rcScrollLeft.right, m_rcScrollLeft.bottom, + m_rcScrollLeft.left, m_rcScrollLeft.bottom - nHalfHeight); + + g.DrawLine( + &pen, + m_rcScrollRight.left, m_rcScrollRight.top, + m_rcScrollRight.left, m_rcScrollRight.bottom); + g.DrawLine( + &pen, + m_rcScrollRight.left, m_rcScrollRight.top, + m_rcScrollRight.right, m_rcScrollRight.top + nHalfHeight); + g.DrawLine( + &pen, + m_rcScrollRight.left, m_rcScrollRight.bottom, + m_rcScrollRight.right, m_rcScrollRight.bottom - nHalfHeight); + } + +#ifdef _DRAW_TAB_RECT + { + Gdiplus::Graphics g(lpNMCustomDraw->nmcd.hdc); + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Lime))); + g.DrawRectangle( + &pen, + m_rcScrollLeft.left, m_rcScrollLeft.top, + m_rcScrollLeft.right - m_rcScrollLeft.left, m_rcScrollLeft.bottom - m_rcScrollLeft.top); + } + { + Gdiplus::Graphics g(lpNMCustomDraw->nmcd.hdc); + Gdiplus::Pen pen(Gdiplus::Color(static_cast(Gdiplus::Color::Magenta))); + g.DrawRectangle( + &pen, + m_rcScrollRight.left, m_rcScrollRight.top, + m_rcScrollRight.right - m_rcScrollRight.left, m_rcScrollRight.bottom - m_rcScrollRight.top); + } +#endif //_DRAW_TAB_RECT + + } + + void CalcSize_CloseButton(LPRECT /*prcTabItemArea*/) + { + DWORD dwStyle = this->GetStyle(); + + if (CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON) && m_Items.GetCount() > 1) + { + SIZE size; + + HTHEME hTheme = ::OpenThemeData(m_hWnd, VSCLASS_WINDOW); + if( hTheme ) + { + ::GetThemePartSize( + hTheme, + NULL, + WP_SMALLCLOSEBUTTON, + 0, + NULL, + TS_TRUE, + &size + ); + + ::CloseThemeData(hTheme); + + m_iCloseButtonWidth = size.cx; + m_iCloseButtonHeight = size.cy; + } + else + { + m_iCloseButtonWidth = 8; + m_iCloseButtonHeight = 8; + } + } + else + { + m_iCloseButtonWidth = 0; + m_iCloseButtonHeight = 0; + } + } + + void CalcSize_ScrollButtons(LPRECT prcTabItemArea) + { + SIZE size; + + HTHEME hTheme = ::OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); + if( hTheme ) + { + ::GetThemePartSize( + hTheme, + NULL, + NAV_BACKBUTTON, + 0, + NULL, + TS_TRUE, + &size + ); + + ::CloseThemeData(hTheme); + } + else + { + size.cx = 16; + size.cy = 16; + } + + 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; + } + + 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); + + int nIconVerticalCenter; + if (CTCS_BOTTOM == (this->GetStyle() & CTCS_BOTTOM)) + { + rcItemDP.top += AERO_FRAME_BORDER_SIZE; + rcItemDP.bottom -= m_iTopMargin; + } + else + { + rcItemDP.top += m_iTopMargin; + rcItemDP.bottom -= AERO_FRAME_BORDER_SIZE; + } + nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top) / 2; + + // calculate the position of the close button + m_rcCloseButton.left = rcItemDP.right; + m_rcCloseButton.right = m_rcCloseButton.left + m_iCloseButtonWidth; + m_rcCloseButton.top = nIconVerticalCenter - m_iCloseButtonHeight / 2; + m_rcCloseButton.bottom = m_rcCloseButton.top + m_iCloseButtonHeight; + } + + 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); + ::OffsetRect(&m_rcCloseButton, m_iScrollOffset, 0); + } + 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); + } + this->UpdateScrollOverflowStatus(); + + dc.SelectFont(hOldFont); + + ::OffsetRect(&m_rcCloseButton, m_iScrollOffset, 0); + if( m_rcCloseButton.right > rcTabItemArea.right ) + m_rcCloseButton.right = rcTabItemArea.right; + } + +}; + +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/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 af206465..daf70a71 100644 --- a/Console/Console.cpp +++ b/Console/Console.cpp @@ -9,6 +9,7 @@ #include "aboutdlg.h" #include "MainFrame.h" #include "Console.h" +#include "WallPaper.h" ////////////////////////////////////////////////////////////////////////////// @@ -23,8 +24,8 @@ CAppModule _Module; -shared_ptr g_settingsHandler; -shared_ptr g_imageHandler; +std::shared_ptr g_settingsHandler; +std::shared_ptr g_imageHandler; ////////////////////////////////////////////////////////////////////////////// @@ -64,16 +65,11 @@ void ParseCommandLine ( LPTSTR lptstrCmdLine, wstring& strConfigFile, - wstring& strWindowTitle, - vector& startupTabs, - vector& startupDirs, - vector& startupCmds, - int& nMultiStartSleep, - wstring& strDbgCmdLine + bool &bReuse ) { - int argc = 0; - shared_array argv(::CommandLineToArgvW(lptstrCmdLine, &argc), ::GlobalFree); + int argc = 0; + std::unique_ptr argv(::CommandLineToArgvW(lptstrCmdLine, &argc)); if (argc < 1) return; @@ -86,57 +82,11 @@ void ParseCommandLine if (i == argc) break; strConfigFile = argv[i]; } - else if (wstring(argv[i]) == wstring(L"-w")) + else if (wstring(argv[i]) == wstring(L"-reuse")) { - // startup tab name - ++i; - if (i == argc) break; - strWindowTitle = argv[i]; - } - else if (wstring(argv[i]) == wstring(L"-t")) - { - // startup tab name - ++i; - if (i == argc) break; - startupTabs.push_back(argv[i]); + bReuse = true; } - else if (wstring(argv[i]) == wstring(L"-d")) - { - // startup dir - ++i; - if (i == argc) break; - startupDirs.push_back(argv[i]); - } - else if (wstring(argv[i]) == wstring(L"-r")) - { - // startup cmd - ++i; - if (i == argc) break; - startupCmds.push_back(argv[i]); - } - else if (wstring(argv[i]) == wstring(L"-ts")) - { - // startup tab sleep for multiple tabs - ++i; - if (i == argc) break; - 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 - if (startupDirs.size() < startupTabs.size()) startupDirs.resize(startupTabs.size()); - if (startupCmds.size() < startupTabs.size()) startupCmds.resize(startupTabs.size()); } ////////////////////////////////////////////////////////////////////////////// @@ -144,66 +94,140 @@ void ParseCommandLine ////////////////////////////////////////////////////////////////////////////// -int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) +static bool HandleReuse(LPCTSTR lpstrCmdLine) { - CMessageLoop theLoop; - _Module.AddMessageLoop(&theLoop); - - wstring strConfigFile(L""); - wstring strWindowTitle(L""); - vector startupTabs; - vector startupDirs; - vector startupCmds; - int nMultiStartSleep = 0; - wstring strDbgCmdLine(L""); - - ParseCommandLine( - lpstrCmdLine, - strConfigFile, - strWindowTitle, - startupTabs, - startupDirs, - startupCmds, - nMultiStartSleep, - strDbgCmdLine); - - if (strConfigFile.length() == 0) - { - strConfigFile = wstring(L"console.xml"); -// strConfigFile = Helpers::GetModulePath(NULL) + wstring(L"console.xml"); -// strConfigFile = wstring(::_wgetenv(L"APPDATA")) + wstring(L"\\Console\\console.xml"); - } - - if (!g_settingsHandler->LoadSettings(Helpers::ExpandEnvironmentStrings(strConfigFile))) + SharedMemory sharedInstance; + try + { + sharedInstance.Open(L"Console", syncObjNone); + } + catch(Win32Exception& ex) + { + if(ex.GetErrorCode() == ERROR_FILE_NOT_FOUND) + return false; + throw; + } + if (0 != sharedInstance.Get()) { - //TODO: error handling - return -1; - } - - // create main window - NoTaskbarParent noTaskbarParent; - MainFrame wndMain(strWindowTitle, startupTabs, startupDirs, startupCmds, nMultiStartSleep, strDbgCmdLine); + ::SetForegroundWindow(*sharedInstance); - if (!g_settingsHandler->GetAppearanceSettings().stylesSettings.bTaskbarButton) - { - noTaskbarParent.Create(NULL); - } + COPYDATASTRUCT cds = {0}; + cds.dwData = 0; + cds.lpData = (LPVOID)lpstrCmdLine; + cds.cbData = static_cast((_tcslen(lpstrCmdLine) + 1) * sizeof(TCHAR)); + + ::SendMessage(*sharedInstance, WM_COPYDATA, 0, (LPARAM)&cds); - if(wndMain.CreateEx(noTaskbarParent.m_hWnd) == NULL) - { - ATLTRACE(_T("Main window creation failed!\n")); - return 0; + return true; } - wndMain.ShowWindow(nCmdShow); - - int nRet = theLoop.Run(); - - if (noTaskbarParent.m_hWnd != NULL) noTaskbarParent.DestroyWindow(); - - _Module.RemoveMessageLoop(); + return false; +} - return nRet; +int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) +{ + try + { + CMessageLoop theLoop; + _Module.AddMessageLoop(&theLoop); + + wstring strConfigFile(L""); + bool bReuse = false; + + ParseCommandLine( + lpstrCmdLine, + strConfigFile, + bReuse); + + if (strConfigFile.length() == 0) + { + strConfigFile = wstring(L"console.xml"); + // strConfigFile = Helpers::GetModulePath(NULL) + wstring(L"console.xml"); + // strConfigFile = wstring(::_wgetenv(L"APPDATA")) + wstring(L"\\Console\\console.xml"); + } + + if (!g_settingsHandler->LoadSettings(Helpers::ExpandEnvironmentStrings(strConfigFile))) + { + throw std::exception("enable to load settings!"); + } + + if (bReuse && HandleReuse(lpstrCmdLine)) + return 0; + + // create main window + NoTaskbarParent noTaskbarParent; + MainFrame wndMain(lpstrCmdLine); + + if (!g_settingsHandler->GetAppearanceSettings().stylesSettings.bTaskbarButton) + { + noTaskbarParent.Create(NULL); + } + + if(wndMain.CreateEx(noTaskbarParent.m_hWnd) == NULL) + { + ATLTRACE(_T("Main window creation failed!\n")); + 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); + + SharedMemory sharedInstance; + if (bReuse) + { + sharedInstance.Create(L"Console", 1, syncObjNone, _T("")); + sharedInstance = wndMain.m_hWnd; + } + + WallPaperThread wallPaperThread(wndMain); + + OSVERSIONINFOEX osvi; + DWORDLONG dwlConditionMask = 0; + BYTE op = VER_GREATER_EQUAL; + + // Initialize the OSVERSIONINFOEX structure. + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = 6; + osvi.dwMinorVersion = 1; + + // Initialize the condition mask. + + VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op ); + VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op ); + + // Perform the test. + + if( VerifyVersionInfo( + &osvi, + VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + dwlConditionMask) ) + { + // Win7 or more, we use the wallpaper slideshow monitoring + wallPaperThread.Start(); + } + + int nRet = theLoop.Run(); + + if (noTaskbarParent.m_hWnd != NULL) noTaskbarParent.DestroyWindow(); + + _Module.RemoveMessageLoop(); + + return nRet; + } + catch(std::exception& e) + { + ::MessageBoxA(0, e.what(), "exception", MB_OK); + return 1; + } } ////////////////////////////////////////////////////////////////////////////// @@ -219,6 +243,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 +263,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.h b/Console/Console.h index b7430279..52f05113 100644 --- a/Console/Console.h +++ b/Console/Console.h @@ -1,5 +1,5 @@ // Console.h #include "SettingsHandler.h" -extern shared_ptr g_settingsHandler; -extern shared_ptr g_imageHandler; \ No newline at end of file +extern std::shared_ptr g_settingsHandler; +extern std::shared_ptr g_imageHandler; \ No newline at end of file diff --git a/Console/Console.rc b/Console/Console.rc index da1ad13a..16451ab0 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -1,6 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" +#include "../shared/version.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -13,13 +14,11 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// Croatian resources +// Croatian (Croatia) 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 ///////////////////////////////////////////////////////////////////////////// @@ -34,174 +33,106 @@ END #endif // APSTUDIO_INVOKED -#endif // Croatian resources -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // -// TEXTINCLUDE +// Dialog // -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE +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 - "#include ""atlres.h""\r\n" - "\0" + 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 + CTEXT "\n&Username:",IDC_STATIC_USER,7,8,42,22 + EDITTEXT IDC_USER,54,13,146,14,ES_AUTOHSCROLL END -#endif // APSTUDIO_INVOKED - ///////////////////////////////////////////////////////////////////////////// // -// Toolbar +// DESIGNINFO // -IDR_MAINFRAME TOOLBAR 16, 16 +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO 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 + 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 (Croatia) resources +///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// +// English (United States) resources -IDR_MAINFRAME BITMAP "res\\Toolbar.bmp" +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // -// Menu +// TEXTINCLUDE // -IDR_MAINFRAME MENU +1 TEXTINCLUDE 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 + "resource.h\0" END -IDR_POPUP_MENU_TAB MENU +2 TEXTINCLUDE 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 + "#include ""atlres.h""\r\n" + "\0" END +#endif // APSTUDIO_INVOKED + ///////////////////////////////////////////////////////////////////////////// // // Dialog // -IDD_ABOUTBOX DIALOGEX 0, 0, 187, 102 +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,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,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 + CTEXT "\nCopyright (C) 2011-2013\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, 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 @@ -218,7 +149,7 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,297,300,50,14 END -IDD_SETTINGS_CONSOLE DIALOGEX 0, 0, 226, 254 +IDD_SETTINGS_CONSOLE DIALOGEX 0, 0, 226, 276 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -254,7 +185,7 @@ BEGIN EDITTEXT IDC_BUFFER_COLUMNS,155,116,40,14,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT CONTROL "",IDC_SPIN_BUFFER_COLUMNS,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,184,116,11,14 GROUPBOX "Buffer size *",IDC_STATIC,110,90,100,57 - GROUPBOX "Console colors map",IDC_STATIC,0,150,210,103 + GROUPBOX "Console colors map",IDC_STATIC,0,150,210,115 CONTROL "",IDC_DEF_00,"Static",SS_BLACKFRAME,10,162,16,14 CONTROL "",IDC_DEF_01,"Static",SS_BLACKFRAME,10,177,16,14 CONTROL "",IDC_DEF_02,"Static",SS_BLACKFRAME,10,192,16,14 @@ -287,7 +218,10 @@ BEGIN CONTROL "",IDC_CLR_13,"Static",SS_BLACKFRAME | SS_NOTIFY,182,177,16,14,WS_EX_DLGMODALFRAME CONTROL "",IDC_CLR_14,"Static",SS_BLACKFRAME | SS_NOTIFY,182,192,16,14,WS_EX_DLGMODALFRAME CONTROL "",IDC_CLR_15,"Static",SS_BLACKFRAME | SS_NOTIFY,182,207,16,14,WS_EX_DLGMODALFRAME - PUSHBUTTON "Re&set",IDC_BTN_RESET_COLORS,153,229,50,14 + PUSHBUTTON "Re&set",IDC_BTN_RESET_COLORS,153,246,50,14 + LTEXT "Background\ntext opacity",IDC_STATIC_BGTEXT_OPACITY,9,224,43,16,NOT WS_GROUP + CONTROL "",IDC_BGTEXT_OPACITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,53,224,129,22 + LTEXT "255",IDC_BGTEXT_OPACITY_VAL,183,226,14,8,0,WS_EX_RIGHT END IDD_SETTINGS_APPEARANCE DIALOGEX 0, 0, 235, 265 @@ -301,47 +235,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 @@ -360,41 +297,45 @@ 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 - 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,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 "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 - 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 - 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,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 + CONTROL "Tas&kbar button *",IDC_CHECK_STYLE_TASKBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,12,68,10 + CONTROL "Tra&y icon",IDC_CHECK_STYLE_TRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,24,45,10 + CONTROL "&Quake like",IDC_CHECK_STYLE_QUAKE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,36,49,10 + LTEXT "Inside &border:",IDC_STATIC,104,72,46,8 + EDITTEXT IDC_INSIDE_BORDER,155,69,33,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,193,69,11,14 + LTEXT "Selection col&or:",IDC_STATIC,103,96,50,8 + CONTROL "",IDC_SELECTION_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,155,93,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 + CONTROL "&Jumplist (Win7)",IDC_CHECK_USE_JUMPLIST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,48,65,10 END IDD_SETTINGS_TEMP DIALOGEX 0, 0, 611, 555 @@ -432,10 +373,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 @@ -447,22 +389,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 @@ -470,24 +414,29 @@ 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 - LTEXT "S&hell:",-1,7,71,23,8 - EDITTEXT IDC_TAB_SHELL,46,68,145,14,ES_AUTOHSCROLL + CONTROL "Use default",IDC_CHECK_DEFAULT_ICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,33,53,10 + 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,160,50,0,WS_EX_TRANSPARENT + CONTROL "Run as &user:",IDC_CHECK_RUN_AS_USER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,58,10 + EDITTEXT IDC_TAB_USER,66,98,99,14,ES_AUTOHSCROLL + CONTROL "&Net only",IDC_CHECK_NET_ONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,100,53,10 + GROUPBOX "Shell",IDC_STATIC,0,55,217,65,WS_GROUP,WS_EX_TRANSPARENT + LTEXT "Style:",IDC_STATIC,5,138,20,8 + COMBOBOX IDC_COMBO_CURSOR,28,136,82,83,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Col&or:",IDC_STATIC,118,138,20,8 + CONTROL "",IDC_CURSOR_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,140,135,16,14,WS_EX_DLGMODALFRAME + CONTROL "",IDC_CURSOR_ANIM,"Static",SS_BLACKRECT | SS_REALSIZEIMAGE | SS_SUNKEN,162,133,30,18 + GROUPBOX "Cursor",IDC_STATIC,0,122,217,35,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 @@ -505,8 +454,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 @@ -538,22 +487,22 @@ END // #ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO +GUIDELINES DESIGNINFO BEGIN IDD_ABOUTBOX, DIALOG 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 @@ -570,6 +519,7 @@ BEGIN IDD_SETTINGS_CONSOLE, DIALOG BEGIN RIGHTMARGIN, 225 + BOTTOMMARGIN, 264 HORZGUIDE, 10 HORZGUIDE, 25 HORZGUIDE, 40 @@ -582,23 +532,23 @@ BEGIN HORZGUIDE, 35 HORZGUIDE, 45 HORZGUIDE, 55 - HORZGUIDE, 75 - HORZGUIDE, 90 - HORZGUIDE, 100 + HORZGUIDE, 70 END IDD_SETTINGS_STYLES, DIALOG BEGIN - VERTGUIDE, 10 - BOTTOMMARGIN, 254 + VERTGUIDE, 6 + VERTGUIDE, 102 + VERTGUIDE, 156 HORZGUIDE, 17 HORZGUIDE, 29 HORZGUIDE, 41 HORZGUIDE, 53 HORZGUIDE, 65 - HORZGUIDE, 78 - HORZGUIDE, 90 - HORZGUIDE, 98 + HORZGUIDE, 76 + HORZGUIDE, 88 + HORZGUIDE, 100 + HORZGUIDE, 111 END IDD_SETTINGS_TEMP, DIALOG @@ -632,11 +582,17 @@ BEGIN IDD_SETTINGS_TABS_1, DIALOG BEGIN - HORZGUIDE, 20 - HORZGUIDE, 72 - HORZGUIDE, 87 - HORZGUIDE, 124 - HORZGUIDE, 142 + VERTGUIDE, 51 + VERTGUIDE, 133 + VERTGUIDE, 190 + VERTGUIDE, 217 + HORZGUIDE, 23 + HORZGUIDE, 38 + HORZGUIDE, 75 + HORZGUIDE, 90 + HORZGUIDE, 105 + HORZGUIDE, 120 + HORZGUIDE, 140 END IDD_SETTINGS_TABS_2, DIALOG @@ -648,14 +604,129 @@ 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 "Select &All", ID_EDIT_SELECT_ALL + MENUITEM "Cl&ear Selection", ID_EDIT_CLEAR_SELECTION + 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 // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,146 - PRODUCTVERSION 2,0,0,146 + FILEVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD2 + PRODUCTVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD2 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -671,15 +742,14 @@ BEGIN BLOCK "000004b0" 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 "InternalName", "Console" - VALUE "LegalCopyright", "Copyright © 2001-2010 Marko Bozikovic" - VALUE "LegalTrademarks", "Copyright © 2001-2010 Marko Bozikovic" + VALUE "FileVersion", VERSION_FILE + VALUE "InternalName", "ConsoleZ" + VALUE "LegalCopyright", VERSION_COPYRIGHT + VALUE "LegalTrademarks", VERSION_COPYRIGHT VALUE "OriginalFilename", "Console.exe" - VALUE "ProductName", "Console" - VALUE "ProductVersion", "2, 0, 0, 146" + VALUE "ProductName", "ConsoleZ" + VALUE "ProductVersion", VERSION_PRODUCT END END BLOCK "VarFileInfo" @@ -782,18 +852,25 @@ BEGIN END +///////////////////////////////////////////////////////////////////////////// +// +// HTML +// + +CONSOLE.XML HTML "..\\setup\\config\\console.xml" + ///////////////////////////////////////////////////////////////////////////// // // String Table // -STRINGTABLE +STRINGTABLE BEGIN IDR_MAINFRAME "Console" IDS_TAB_CREATE_FAILED "Failed to open %s tab!\nThe process %s could still be running (use the Task Manager to find it and end it)" END -STRINGTABLE +STRINGTABLE BEGIN ID_FILE_NEW "Create a new document\nNew" ID_FILE_OPEN "Open an existing document\nOpen" @@ -806,20 +883,20 @@ BEGIN ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview" END -STRINGTABLE +STRINGTABLE BEGIN ID_APP_ABOUT "Display program information, version number and copyright\nAbout" ID_APP_EXIT "Quit the application; prompts to save documents\nExit" ID_HELP "Opens the help file\nHelp" END -STRINGTABLE +STRINGTABLE BEGIN ID_NEXT_PANE "Switch to the next window pane\nNext Pane" ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane" END -STRINGTABLE +STRINGTABLE BEGIN ID_WINDOW_NEW "Open another window for the active document\nNew Window" ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons" @@ -829,7 +906,7 @@ BEGIN ID_WINDOW_SPLIT "Split the active window into panes\nSplit" END -STRINGTABLE +STRINGTABLE BEGIN ID_EDIT_CLEAR "Erase the selection\nErase" ID_EDIT_CLEAR_ALL "Erase everything\nErase All" @@ -844,13 +921,25 @@ BEGIN ID_EDIT_REDO "Redo the previously undone action\nRedo" END -STRINGTABLE +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_TOOLBAR "Show or hide the toolbar\nToggle ToolBar" - ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar" + ID_VIEW_MENU "Show or hide the menu" + ID_VIEW_TABS "Show or hide the tabs" END -STRINGTABLE +STRINGTABLE +BEGIN + ID_VIEW_TOOLBAR "Show or hide the toolbar" + ID_VIEW_STATUS_BAR "Show or hide the status bar" +END + +STRINGTABLE BEGIN ATL_IDS_SCSIZE "Change the window size" ATL_IDS_SCMOVE "Change the window position" @@ -861,40 +950,75 @@ BEGIN ATL_IDS_SCCLOSE "Close the active window and prompts to save the documents" END -STRINGTABLE +STRINGTABLE BEGIN ATL_IDS_SCRESTORE "Restore the window to normal size" ATL_IDS_SCTASKLIST "Activate Task List" ATL_IDS_MDICHILD "Activate this window" END -STRINGTABLE +STRINGTABLE BEGIN ATL_IDS_IDLEMESSAGE "Ready" END -STRINGTABLE +STRINGTABLE BEGIN ATL_IDS_MRU_FILE "Open this document" END -STRINGTABLE +STRINGTABLE BEGIN - ID_FILE_NEW_TAB "Opens a new tab\nNew tab" + 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 +STRINGTABLE BEGIN - ID_NEXT_TAB "Switch to next tab\nNext tab" - ID_PREV_TAB "Switch to previous tab\nPrevious tab" + IDPANE_COLUMNS_ROWS "000x000" + IDPANE_CAPS_INDICATOR "CAPS" + IDPANE_NUM_INDICATOR "NUM" + IDPANE_SCRL_INDICATOR "SCRL" + IDPANE_PID_INDICATOR "000000" + IDPANE_SELECTION "00000000" + IDPANE_BUF_COLUMNS_ROWS "0000x0000" END -STRINGTABLE +STRINGTABLE BEGIN - IDPANE_ROWS_COLUMNS "%ix%i" + IDS_ERR_CANT_START_SHELL "Unable to start %1% (reason:%2%)!" + IDS_ERR_CANT_START_SHELL_AS_USER "Unable to start %1% as user %2% (reason:%3%)!" + IDS_ERR_DLL_INJECTION_FAILED "DLL injection has failed (reason:%1%)!" + IDS_ERR_DLL_HOOK_MISSING "DLL hook %1% is missing!" + IDS_ERR_CREATE_SHARED_OBJECTS_FAILED "Unable to create shared objects (reason:%1%)!" END -#endif // English (U.S.) resources +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 + +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 (United States) resources ///////////////////////////////////////////////////////////////////////////// @@ -904,7 +1028,8 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - + + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/Console.vcproj b/Console/Console.vcproj deleted file mode 100644 index 73a67326..00000000 --- a/Console/Console.vcproj +++ /dev/null @@ -1,781 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Console/Console.vcxproj b/Console/Console.vcxproj new file mode 100644 index 00000000..391e5415 --- /dev/null +++ b/Console/Console.vcxproj @@ -0,0 +1,741 @@ + + + + + Debug aero + Win32 + + + Debug aero + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release aero + Win32 + + + Release aero + x64 + + + Release + Win32 + + + Release + x64 + + + + {6EA5C354-A242-49F3-88D1-559EACA7FB8A} + Console + + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + Application + Unicode + v110 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + ..\bin\$(Platform)\$(Configuration)\ + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + false + ..\bin\$(Platform)\$(Configuration)\ + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\i386;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\i386;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\i386;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\i386;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\amd64;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\amd64;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\amd64;$(LibraryPath) + + + C:\WinDDK\7600.16385.1\inc\atl71;G:\gitstuff\boost_1_52_0;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\ATL\amd64;$(LibraryPath) + + + + _DEBUG;%(PreprocessorDefinitions) + false + Win32 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + Disabled + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + true + Windows + false + + + MachineX86 + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + _DEBUG;%(PreprocessorDefinitions) + false + Win32 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + Disabled + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;_USE_AERO;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + _DEBUG;_USE_AERO;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;Credui.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + true + Windows + false + + + MachineX86 + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + _DEBUG;%(PreprocessorDefinitions) + false + X64 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + Disabled + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\x64\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + true + Windows + false + + + MachineX64 + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\x64\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\x64\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + _DEBUG;%(PreprocessorDefinitions) + false + X64 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + Disabled + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;_USE_AERO;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + _DEBUG;_USE_AERO;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\x64\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;Credui.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + true + Windows + false + + + MachineX64 + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\x64\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\x64\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + NDEBUG;%(PreprocessorDefinitions) + false + Win32 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) + Sync + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + Windows + false + + + MachineX86 + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) + Sync + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\x64\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + Windows + false + + + MachineX64 + + + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\x64\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\x64\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + false + Win32 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;NDEBUG;_USE_AERO;%(PreprocessorDefinitions) + Sync + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + NDEBUG;_USE_AERO;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;Credui.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + true + $(TargetDir)$(TargetName).pdb + Windows + false + + + MachineX86 + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + res\Console.exe.manifest;%(AdditionalManifestFiles) + + + FreeImage + copy "..\setup\dlls\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + NDEBUG;%(PreprocessorDefinitions) + false + X64 + true + $(IntDir)Console.tlb + Console.h + + + Console_i.c + Console_p.c + + + /Zm200 + ../TabbingFramework;../wtl/wtl/include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;STRICT;NDEBUG;_USE_AERO;%(PreprocessorDefinitions) + Sync + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + NDEBUG;_USE_AERO;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);../wtl/wtl/include;%(AdditionalIncludeDirectories) + + + ..\FreeImage\x64\FreeImagePlus.lib;delayimp.lib;htmlhelp.lib;userenv.lib;Credui.lib;%(AdditionalDependencies) + uxtheme.dll;%(DelayLoadDLLs) + Windows + false + + + MachineX64 + true + olepro32.lib;%(IgnoreSpecificDefaultLibraries) + + + FreeImage + copy "..\setup\dlls\x64\FreeImage.dll" "..\bin\$(Platform)\$(Configuration)\" +copy "..\setup\dlls\x64\FreeImagePlus.dll" "..\bin\$(Platform)\$(Configuration)\" + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Build CHM file + hhc "%(FullPath)" +if errorlevel 1 ( +copy "%(RootDir)%(Directory)%(Filename).chm" "$(TargetDir)" +exit 0 ) +echo %(Filename)%(Extension) : error : failed to create CHM file + + %(RootDir)%(Directory)%(Filename).chm;%(Outputs) + hhc "%(FullPath)" +if errorlevel 1 ( +copy "%(RootDir)%(Directory)%(Filename).chm" "$(TargetDir)" +exit 0 ) +echo %(Filename)%(Extension) : error : failed to create CHM file + + Build CHM file + %(RootDir)%(Directory)%(Filename).chm;%(Outputs) + hhc "%(FullPath)" +if errorlevel 1 ( +copy "%(RootDir)%(Directory)%(Filename).chm" "$(TargetDir)" +exit 0 ) +echo %(Filename)%(Extension) : error : failed to create CHM file + + Build CHM file + %(RootDir)%(Directory)%(Filename).chm;%(Outputs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Console/Console.vcxproj.filters b/Console/Console.vcxproj.filters new file mode 100644 index 00000000..b6cb174a --- /dev/null +++ b/Console/Console.vcxproj.filters @@ -0,0 +1,321 @@ + + + + + {38d62e3c-568f-46bc-83f7-e2b3b465acf7} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {087b0ad6-deee-4525-a11b-2a855bd32aa5} + h;hpp;hxx;hm;inl;inc + + + {4489e1b3-a800-45a7-8ae5-ca49ea815733} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest + + + {cc4765aa-179c-439b-83ac-a4bb303faca5} + + + {44a4528b-d8da-4212-aa2b-1f4888f80c0a} + + + {5fe3ba1d-76b1-443d-a80c-c5a24a502a52} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Help Files + + + Help Files + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html + + + Help Files\html\styles + + + Resource Files + + + + + Resource Files + + + + + Help Files + + + \ No newline at end of file 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 4a920fdd..12c3f7a1 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -1,8 +1,10 @@ #include "stdafx.h" +#include "resource.h" #include "Console.h" #include "../shared/SharedMemNames.h" +#include "ConsoleException.h" #include "ConsoleHandler.h" ////////////////////////////////////////////////////////////////////////////// @@ -21,7 +23,8 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -shared_ptr ConsoleHandler::s_environmentBlock; +std::shared_ptr ConsoleHandler::s_parentProcessWatchdog; +std::shared_ptr ConsoleHandler::s_environmentBlock; ////////////////////////////////////////////////////////////////////////////// @@ -31,12 +34,14 @@ ConsoleHandler::ConsoleHandler() , m_consoleInfo() , m_consoleBuffer() , m_consoleCopyInfo() -, m_consolePasteInfo() +, m_consoleTextInfo() , m_consoleMouseEvent() , m_newConsoleSize() , m_newScrollPos() , m_hMonitorThread() -, m_hMonitorThreadExit(shared_ptr(::CreateEvent(NULL, FALSE, FALSE, NULL), ::CloseHandle)) +, m_hMonitorThreadExit(std::shared_ptr(::CreateEvent(NULL, FALSE, FALSE, NULL), ::CloseHandle)) +, m_bufferMutex(NULL, FALSE, NULL) +, m_dwConsolePid(0) { } @@ -69,26 +74,120 @@ 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 UserCredentials& userCredentials, + const wstring& strInitialCmd, + const wstring& strConsoleTitle, + DWORD dwStartupRows, + DWORD dwStartupColumns +) { + wstring strUsername(userCredentials.user); + wstring strDomain; + + //std::shared_ptr userProfileKey; + std::unique_ptr userEnvironment; + std::unique_ptr userToken; + + if (strUsername.length() > 0) + { + size_t pos; + if ((pos= strUsername.find(L'\\')) != wstring::npos) + { + strDomain = strUsername.substr(0, pos); + strUsername = strUsername.substr(pos+1); + } + else if ((pos= strUsername.find(L'@')) != wstring::npos) + { + // UNC format + strDomain = strUsername.substr(pos + 1); + strUsername = strUsername.substr(0, pos); + } + else + { + // CreateProcessWithLogonW & LOGON_NETCREDENTIALS_ONLY fails if domain is NULL + wchar_t szComputerName[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD dwComputerNameLen = ARRAYSIZE(szComputerName); + if( ::GetComputerName(szComputerName, &dwComputerNameLen) ) + strDomain = szComputerName; + } + + if (!userCredentials.netOnly) + { + // logon user + HANDLE hUserToken = NULL; + if( !::LogonUser( + strUsername.c_str(), + strDomain.length() > 0 ? strDomain.c_str() : NULL, + userCredentials.password.c_str(), + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + &hUserToken) || !::ImpersonateLoggedOnUser(hUserToken) ) + { + Win32Exception err(::GetLastError()); + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % L"?" % userCredentials.user % err.what())); + } + userToken.reset(hUserToken); + + /* + // 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 = nullptr; + if( !::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE) ) + { + Win32Exception err(::GetLastError()); + ::RevertToSelf(); + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % L"?" % userCredentials.user % err.what())); + } + userEnvironment.reset(pEnvironment); + } + } + wstring strShellCmdLine(strCustomShell); - + if (strShellCmdLine.length() == 0) { wchar_t szComspec[MAX_PATH]; ::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t)); - if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0) + if (userEnvironment.get()) { - 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"; } } @@ -103,10 +202,13 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr if (strStartupTitle.length() == 0) { strStartupTitle = L"Console2 command window"; -// strStartupTitle = str(wformat(L"Console2 command window 0x%08X") % this); +// strStartupTitle = boost::str(boost::wformat(L"Console2 command window 0x%08X") % this); } - wstring strStartupDir(Helpers::ExpandEnvironmentStrings(strInitialDir)); + wstring strStartupDir( + userToken.get() ? + Helpers::ExpandEnvironmentStringsForUser(userToken.get(), strInitialDir) : + Helpers::ExpandEnvironmentStrings(strInitialDir)); if (strStartupDir.length() > 0) { @@ -133,6 +235,14 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr } } + wstring strCmdLine( + userToken.get() ? + Helpers::ExpandEnvironmentStringsForUser(userToken.get(), strShellCmdLine) : + Helpers::ExpandEnvironmentStrings(strShellCmdLine)); + + if( userToken.get() ) + ::RevertToSelf(); + // setup the startup info struct STARTUPINFO si; ::ZeroMemory(&si, sizeof(STARTUPINFO)); @@ -161,7 +271,7 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr 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; @@ -169,23 +279,66 @@ 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) + { + STARTUPINFO si; + ::ZeroMemory(&si, sizeof(STARTUPINFO)); + + si.cb = sizeof(STARTUPINFO); + + if( !::CreateProcessWithLogonW( + strUsername.c_str(), + strDomain.length() > 0 ? strDomain.c_str() : NULL, + userCredentials.password.c_str(), + userCredentials.netOnly? LOGON_NETCREDENTIALS_ONLY : LOGON_WITH_PROFILE, NULL, - FALSE, + const_cast(strCmdLine.c_str()), dwStartupFlags, s_environmentBlock.get(), (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, &si, &pi)) + { + Win32Exception err(::GetLastError()); + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % strShellCmdLine % userCredentials.user % err.what())); + } + } + else { - return false; + if (!::CreateProcess( + NULL, + const_cast(strCmdLine.c_str()), + NULL, + NULL, + FALSE, + dwStartupFlags, + s_environmentBlock.get(), + (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, + &si, + &pi)) + { + Win32Exception err(::GetLastError()); + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_CANT_START_SHELL)) % strShellCmdLine % err.what())); + } } // create shared memory objects - CreateSharedObjects(pi.dwProcessId); + try + { + std::wstring strAccountName; + if( !userCredentials.netOnly && !userCredentials.user.empty() ) + { + if( !strDomain.empty() ) + strAccountName = strDomain + L"\\"; + strAccountName += strUsername; + } + CreateSharedObjects(pi.dwProcessId, strAccountName); + CreateWatchdog(); + } + catch(Win32Exception& err) + { + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_CREATE_SHARED_OBJECTS_FAILED)) % err.what())); + } // write startup params m_consoleParams->dwConsoleMainThreadId = pi.dwThreadId; @@ -197,17 +350,20 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr m_consoleParams->dwBufferRows = g_settingsHandler->GetConsoleSettings().dwBufferRows; m_consoleParams->dwBufferColumns = g_settingsHandler->GetConsoleSettings().dwBufferColumns; - m_hConsoleProcess = shared_ptr(pi.hProcess, ::CloseHandle); + m_hConsoleProcess = std::shared_ptr(pi.hProcess, ::CloseHandle); + m_dwConsolePid = pi.dwProcessId; // inject our hook DLL into console process - if (!InjectHookDLL()) return false; + if (!InjectHookDLL(pi)) + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % L"?")); // resume the console process ::ResumeThread(pi.hThread); ::CloseHandle(pi.hThread); // wait for hook DLL to set console handle - if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT) return false; + if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT) + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % L"timeout")); ::ShowWindow(m_consoleParams->hwndConsoleWindow, SW_HIDE); @@ -222,7 +378,7 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr DWORD ConsoleHandler::StartMonitorThread() { DWORD dwThreadId = 0; - m_hMonitorThread = shared_ptr( + m_hMonitorThread = std::shared_ptr( ::CreateThread( NULL, 0, @@ -319,22 +475,21 @@ 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; @@ -343,25 +498,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); - // 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, 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; } @@ -370,57 +524,264 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId) ////////////////////////////////////////////////////////////////////////////// -bool ConsoleHandler::InjectHookDLL() +void ConsoleHandler::CreateWatchdog() +{ + if (!s_parentProcessWatchdog) + { + std::shared_ptr sd; // PSECURITY_DESCRIPTOR + + sd.reset(::LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH), ::LocalFree); + if (::InitializeSecurityDescriptor(sd.get(), SECURITY_DESCRIPTOR_REVISION)) + { + ::SetSecurityDescriptorDacl( + sd.get(), + TRUE, // bDaclPresent flag + NULL, // full access to everyone + FALSE); // not a default DACL + } + + 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()))); + } +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +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; - - 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.get() == NULL) return false; - - // write the memory - if (!::WriteProcessMemory( - m_hConsoleProcess.get(), - (PVOID)pszHookDllPathRemote.get(), - (PVOID)strHookDllPath.c_str(), - strHookDllPath.length()*sizeof(wchar_t), - NULL)) + wstring strHookDllPath(GetModulePath(NULL)); + + CONTEXT context; + + void* mem = NULL; + size_t memLen = 0; + UINT_PTR fnLoadLibrary = NULL; + + size_t codeSize; + BOOL isWow64Process = FALSE; + +#ifdef _WIN64 + WOW64_CONTEXT wow64Context; + DWORD fnWow64LoadLibrary = 0; + + ::ZeroMemory(&wow64Context, sizeof(WOW64_CONTEXT)); + ::IsWow64Process(pi.hProcess, &isWow64Process); + codeSize = isWow64Process ? 20 : 91; +#else + codeSize = 20; +#endif + + if (isWow64Process) + { + // starting a 32-bit process from a 64-bit console + strHookDllPath += wstring(L"\\ConsoleHook32.dll"); + } + else { - return false; + // same bitness :-) + strHookDllPath += wstring(L"\\ConsoleHook.dll"); } - // get address to LoadLibraryW function - PTHREAD_START_ROUTINE pfnThreadRoutine = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(L"Kernel32.dll"), "LoadLibraryW"); - if (pfnThreadRoutine == NULL) return false; + if (::GetFileAttributes(strHookDllPath.c_str()) == INVALID_FILE_ATTRIBUTES) + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_HOOK_MISSING)) % strHookDllPath.c_str())); + + ::ZeroMemory(&context, sizeof(CONTEXT)); - // start the remote thread - hRemoteThread = shared_ptr( - ::CreateRemoteThread( - m_hConsoleProcess.get(), - NULL, - 0, - pfnThreadRoutine, - (PVOID)pszHookDllPathRemote.get(), - 0, - NULL), - ::CloseHandle); + memLen = (strHookDllPath.length()+1)*sizeof(wchar_t); + std::unique_ptr code(new BYTE[codeSize + memLen]); - if (hRemoteThread.get() == NULL) return false; + ::CopyMemory(code.get() + codeSize, strHookDllPath.c_str(), memLen); + memLen += codeSize; - // wait for the thread to finish -// ::WaitForSingleObject(hRemoteThread.get(), INFINITE); - if (::WaitForSingleObject(hRemoteThread.get(), 10000) == WAIT_TIMEOUT) return false; +#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 siWow; + ::ZeroMemory(&siWow, sizeof(STARTUPINFO)); + + siWow.cb = sizeof(STARTUPINFO); + siWow.dwFlags = STARTF_USESHOWWINDOW; + siWow.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION piWow; + + if (!::CreateProcess( + NULL, + const_cast(strConsoleWowPath.c_str()), + NULL, + NULL, + FALSE, + 0, + NULL, + NULL, + &siWow, + &piWow)) + { + Win32Exception err(::GetLastError()); + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_CANT_START_SHELL)) % strConsoleWowPath.c_str() % err.what())); + } + + std::shared_ptr wowProcess(piWow.hProcess, ::CloseHandle); + std::shared_ptr wowThread(piWow.hThread, ::CloseHandle); + + if (::WaitForSingleObject(wowProcess.get(), 5000) == WAIT_TIMEOUT) + { + throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_DLL_INJECTION_FAILED)) % L"timeout")); + } + + ::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++ = static_cast(reinterpret_cast(mem) + codeSize); + *ip.pB++ = 0xe8; // call LoadLibraryW + *ip.pI++ = static_cast(fnWow64LoadLibrary - (reinterpret_cast(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 = static_cast(reinterpret_cast(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 = reinterpret_cast(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++ = reinterpret_cast(mem) + codeSize; + *ip.pB++ = 0xe8; // call LoadLibraryW + *ip.pI++ = fnLoadLibrary - (reinterpret_cast(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 = reinterpret_cast(mem); + ::SetThreadContext(pi.hThread, &context); +#endif return true; } @@ -448,19 +809,16 @@ 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) { - 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) || @@ -468,6 +826,8 @@ DWORD ConsoleHandler::MonitorThread() ((m_consoleParams->dwBufferColumns != 0) && (m_consoleParams->dwBufferColumns != dwBufferColumns)) || ((m_consoleParams->dwBufferRows != 0) && (m_consoleParams->dwBufferRows != dwBufferRows))) { + MutexLock handlerLock(m_bufferMutex); + m_consoleParams->dwColumns = dwColumns; m_consoleParams->dwRows = dwRows; diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index 0f8529aa..b1739286 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -11,6 +11,36 @@ typedef fastdelegate::FastDelegate1 ConsoleChangeDelegate; typedef fastdelegate::FastDelegate0<> ConsoleCloseDelegate; +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +struct UserCredentials +{ + UserCredentials() + : user() + , password() + , netOnly(false) + { + } + + ~UserCredentials() + { + if (password.length() > 0) + { + ::SecureZeroMemory(reinterpret_cast(const_cast(password.c_str())), password.length()); + } + } + + wstring user; + wstring password; + bool netOnly; +}; + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// class ConsoleHandler @@ -19,22 +49,33 @@ class ConsoleHandler ConsoleHandler(); ~ConsoleHandler(); + Mutex m_bufferMutex; + 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 UserCredentials& userCredentials, + const wstring& strInitialCmd, + const wstring& strConsoleTitle, + DWORD dwStartupRows, + DWORD dwStartupColumns + ); DWORD StartMonitorThread(); void StopMonitorThread(); - shared_ptr GetConsoleHandle() const { return m_hConsoleProcess; } + std::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; } - SharedMemory& GetPasteInfo() { return m_consolePasteInfo; } + SharedMemory& GetTextInfo() { return m_consoleTextInfo; } SharedMemory& GetNewConsoleSize() { return m_newConsoleSize; } SharedMemory& GetNewScrollPos() { return m_newScrollPos; } @@ -45,45 +86,52 @@ class ConsoleHandler static void UpdateEnvironmentBlock(); + inline DWORD GetConsolePid(void) const { return m_dwConsolePid; } + private: - bool CreateSharedObjects(DWORD dwConsoleProcessId); + bool CreateSharedObjects(DWORD dwConsoleProcessId, const wstring& strUser); + void CreateWatchdog(); - bool InjectHookDLL(); + bool InjectHookDLL(PROCESS_INFORMATION& pi); private: - + static DWORD WINAPI MonitorThreadStatic(LPVOID lpParameter); DWORD MonitorThread(); private: - + wstring GetModulePath(HMODULE hModule); private: - ConsoleChangeDelegate m_consoleChangeDelegate; - ConsoleCloseDelegate m_consoleCloseDelegate; + ConsoleChangeDelegate m_consoleChangeDelegate; + ConsoleCloseDelegate m_consoleCloseDelegate; + + std::shared_ptr m_hConsoleProcess; + + SharedMemory m_consoleParams; + SharedMemory m_consoleInfo; + SharedMemory m_cursorInfo; + SharedMemory m_consoleBuffer; + SharedMemory m_consoleCopyInfo; + SharedMemory m_consoleTextInfo; + SharedMemory m_consoleMouseEvent; - shared_ptr m_hConsoleProcess; + SharedMemory m_newConsoleSize; + SharedMemory m_newScrollPos; - SharedMemory m_consoleParams; - SharedMemory m_consoleInfo; - SharedMemory m_cursorInfo; - SharedMemory m_consoleBuffer; - SharedMemory m_consoleCopyInfo; - SharedMemory m_consolePasteInfo; - SharedMemory m_consoleMouseEvent; + std::shared_ptr m_hMonitorThread; + std::shared_ptr m_hMonitorThreadExit; - SharedMemory m_newConsoleSize; - SharedMemory m_newScrollPos; + static std::shared_ptr s_environmentBlock; + static std::shared_ptr s_parentProcessWatchdog; - shared_ptr m_hMonitorThread; - shared_ptr m_hMonitorThreadExit; + DWORD m_dwConsolePid; - static shared_ptr s_environmentBlock; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 50e34848..ab6c8dd9 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -4,8 +4,9 @@ #include #include "Console.h" -#include "MainFrame.h" +#include "ConsoleException.h" #include "ConsoleView.h" +#include "MainFrame.h" ////////////////////////////////////////////////////////////////////////////// @@ -14,59 +15,72 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -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_nVScrollWidth(0); +int ConsoleView::m_nHScrollWidth(0); +int ConsoleView::m_nVInsideBorder(0); +int ConsoleView::m_nHInsideBorder(0); -int ConsoleView::m_nCharHeight(0); -int ConsoleView::m_nCharWidth(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, std::shared_ptr tabData, const CString& strTitle, DWORD dwRows, DWORD dwColumns, const wstring& strCmdLineInitialDir /*= wstring(L"")*/, const wstring& strCmdLineInitialCmd /*= wstring(L"")*/) : m_mainFrame(mainFrame) -, m_strCmdLineInitialDir(strCmdLineInitialDir) -, m_strInitialCmd(strInitialCmd) -, m_strDbgCmdLine(strDbgCmdLine) +, m_hwndTabView(hwndTabView) , m_bInitializing(true) , m_bResizing(false) , m_bAppActive(true) , m_bActive(true) -, m_bNeedFullRepaint(false) // first OnPaint will do a full repaint +, m_bNeedFullRepaint(true) // first OnPaint will do a full repaint , m_bUseTextAlphaBlend(false) , m_bConsoleWindowVisible(false) , m_dwStartupRows(dwRows) , m_dwStartupColumns(dwColumns) +, m_dwVScrollMax(0) +, m_nVWheelDelta(0) , m_bShowVScroll(false) , m_bShowHScroll(false) -, m_nVScrollWidth(::GetSystemMetrics(SM_CXVSCROLL)) -, m_nHScrollWidth(::GetSystemMetrics(SM_CXHSCROLL)) -, m_strTitle(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str()) -, bigIcon() -, smallIcon() +, m_strTitle(strTitle) +, m_strUser() +, m_boolNetOnly(false) , 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()) -, m_tabData(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]) +, m_tabData(tabData) , m_background() , m_backgroundBrush(NULL) , m_cursor() , m_selectionHandler() , m_mouseCommand(MouseSettings::cmdNone) -, m_bufferMutex(NULL, FALSE, NULL) , m_bFlashTimerRunning(false) , m_dwFlashes(0) +, m_dcOffscreen(::CreateCompatibleDC(NULL)) +, m_dcText(::CreateCompatibleDC(NULL)) +, m_boolIsGrouped(false) +, m_strCmdLineInitialDir(strCmdLineInitialDir) +, m_strCmdLineInitialCmd(strCmdLineInitialCmd) { } ConsoleView::~ConsoleView() { +#ifdef _USE_AERO + // remove the console view from taskbar list + m_mainFrame.m_taskBarList.RemoveTab(this); +#endif } ////////////////////////////////////////////////////////////////////////////// @@ -105,54 +119,13 @@ 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); - 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)); - } - // set console delegates m_consoleHandler.SetupDelegates( - fastdelegate::MakeDelegate(this, &ConsoleView::OnConsoleChange), + fastdelegate::MakeDelegate(this, &ConsoleView::OnConsoleChange), fastdelegate::MakeDelegate(this, &ConsoleView::OnConsoleClose)); // load background image @@ -165,7 +138,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); @@ -180,30 +153,38 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* } 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; } - if (!m_consoleHandler.StartShellProcess( - strShell, - strInitialDir, - m_strInitialCmd, - g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), - m_dwStartupRows, - m_dwStartupColumns, - bDebugFlag)) + try { + CREATESTRUCT* createStruct = reinterpret_cast(lParam); + UserCredentials* userCredentials = reinterpret_cast(createStruct->lpCreateParams); + + m_consoleHandler.StartShellProcess( + strShell, + strInitialDir, + *userCredentials, + m_strCmdLineInitialCmd, + g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), + m_dwStartupRows, + m_dwStartupColumns); + + m_strUser = userCredentials->user.c_str(); + m_boolNetOnly = userCredentials->netOnly; + } + catch (const ConsoleException& ex) + { + m_exceptionMessage = ex.GetMessage().c_str(); return -1; } + // set view title + SetTitle(m_strTitle); + m_bInitializing = false; // set current language in the console window @@ -216,12 +197,16 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* // scrollbar stuff InitializeScrollbars(); + // create font + RecreateFont(); + // create offscreen buffers CreateOffscreenBuffers(); // 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_dwScreenRows = m_consoleHandler.GetConsoleParams()->dwRows; + m_dwScreenColumns = m_consoleHandler.GetConsoleParams()->dwColumns; + m_screenBuffer.reset(new CharInfo[m_dwScreenRows * m_dwScreenColumns]); m_consoleHandler.StartMonitorThread(); @@ -262,6 +247,7 @@ LRESULT ConsoleView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ if (m_bNeedFullRepaint) { + //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); @@ -275,7 +261,7 @@ LRESULT ConsoleView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ { dc.FillRect(&dc.m_ps.rcPaint, m_backgroundBrush); } - + dc.BitBlt( dc.m_ps.rcPaint.left, dc.m_ps.rcPaint.top, @@ -293,11 +279,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); @@ -331,16 +322,83 @@ 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 (!TranslateKeyDown(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); + //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; } +LRESULT ConsoleView::OnMouseWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + UINT uKeys = GET_KEYSTATE_WPARAM(wParam); + int nWheelDelta = GET_WHEEL_DELTA_WPARAM(wParam); + int nScrollDelta = m_nVWheelDelta + nWheelDelta; + + m_nVWheelDelta = nScrollDelta % WHEEL_DELTA; + nScrollDelta = nScrollDelta / WHEEL_DELTA; + + if (nScrollDelta != 0) + { + if (uKeys & MK_CONTROL) + { + // calculate new font size in the [5, 36] interval + DWORD size = max(5, min(36, m_appearanceSettings.fontSettings.dwSize + nScrollDelta)); + + // 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; + // recreate font with new size + RecreateFont(); + m_mainFrame.AdjustWindowSize(ADJUSTSIZE_FONT); + } + } + else + { + if (uKeys & MK_SHIFT) + { + // scroll pages + ScrollSettings& scrollSettings = g_settingsHandler->GetBehaviorSettings().scrollSettings; + if (scrollSettings.dwPageScrollRows > 0) + { + // modified behavior: pagescroll = x lines + nScrollDelta *= static_cast(scrollSettings.dwPageScrollRows); + } + else + { + nScrollDelta *= static_cast(m_consoleHandler.GetConsoleParams()->dwRows); + } + } + else + { + // scroll lines + UINT uScrollAmount; + if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uScrollAmount, 0)) + uScrollAmount = 3; + nScrollDelta *= static_cast(uScrollAmount); + } + DoScroll(SB_VERT, SB_THUMBPOSITION, ::FlatSB_GetScrollPos(m_hWnd, SB_VERT) - nScrollDelta); + } + } + + return 0; +} + + ////////////////////////////////////////////////////////////////////////////// @@ -473,13 +531,27 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL { ::SetCursor(::LoadCursor(NULL, IDC_IBEAM)); - MutexLock bufferLock(m_bufferMutex); - m_selectionHandler->StartSelection(GetConsoleCoord(point), m_appearanceSettings.stylesSettings.crSelectionColor, m_screenBuffer); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + m_selectionHandler->StartSelection(GetConsoleCoord(point, true), m_screenBuffer.get()); 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_consoleHandler.m_bufferMutex); + m_selectionHandler->SelectWord(GetConsoleCoord(point), m_screenBuffer.get()); + } + + mouseAction.clickType = MouseSettings::clickDouble; + } + // paste command it = mouseSettings.commands.get().find(MouseSettings::cmdPaste); if ((*it)->action == mouseAction) @@ -529,7 +601,8 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL m_selectionHandler->EndSelection(); 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(); @@ -545,7 +618,8 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL case MouseSettings::cmdPaste : { - Paste(); + //Paste(); + m_mainFrame.PasteToConsoles(); break; } @@ -589,29 +663,27 @@ 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); } { - MutexLock bufferLock(m_bufferMutex); - m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer.get()); } BitBltOffscreen(); @@ -682,12 +754,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); @@ -761,8 +833,11 @@ LRESULT ConsoleView::OnDropFiles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/ } ::DragFinish(hDrop); - // TODO: fix this - SendTextToConsole(strFilenames); + if( this->IsGrouped() ) + m_mainFrame.SendTextToConsole(strFilenames); + else + SendTextToConsole(strFilenames); + return 0; } @@ -775,7 +850,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) @@ -786,8 +862,6 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* */ InitializeScrollbars(); - if (m_bActive) RecreateOffscreenBuffers(); - // notify parent about resize m_mainFrame.SendMessage(UM_CONSOLE_RESIZED, 0, 0); } @@ -797,30 +871,39 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* // if the view is not visible, don't repaint 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; } - SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); + + m_dwVScrollMax = max(m_dwVScrollMax, static_cast(consoleInfo->csbi.srWindow.Bottom)); if (m_bShowVScroll) { SCROLLINFO si; - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - si.nPos = consoleInfo->srWindow.Top; + si.cbSize = sizeof(si); + si.fMask = SIF_POS | SIF_RANGE; + si.nPos = consoleInfo->csbi.srWindow.Top; + si.nMax = m_dwVScrollMax; + si.nMin = 0; ::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); */ } @@ -829,7 +912,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); } @@ -840,8 +923,8 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* ::GetCursorPos(&point); ScreenToClient(&point); - MutexLock bufferLock(m_bufferMutex); - m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer.get()); } else if (m_selectionHandler->GetState() == SelectionHandler::selstateSelected) { @@ -853,81 +936,6 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* return 0; } -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -LRESULT ConsoleView::OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled) -{ - int nScrollType = 0; - int nScrollCode = 0; - - switch (wID) - { - case ID_SCROLL_UP : - { - nScrollType = SB_VERT; - nScrollCode = SB_LINEUP; - break; - } - - case ID_SCROLL_LEFT : - { - nScrollType = SB_HORZ; - nScrollCode = SB_LINELEFT; - break; - } - - case ID_SCROLL_DOWN : - { - nScrollType = SB_VERT; - nScrollCode = SB_LINEDOWN; - break; - } - - case ID_SCROLL_RIGHT : - { - nScrollType = SB_HORZ; - nScrollCode = SB_LINERIGHT; - break; - } - - case ID_SCROLL_PAGE_UP : - { - nScrollType = SB_VERT; - nScrollCode = SB_PAGEUP; - break; - } - - case ID_SCROLL_PAGE_LEFT : - { - nScrollType = SB_HORZ; - nScrollCode = SB_PAGELEFT; - break; - } - - case ID_SCROLL_PAGE_DOWN : - { - nScrollType = SB_VERT; - nScrollCode = SB_PAGEDOWN; - break; - } - - case ID_SCROLL_PAGE_RIGHT : - { - nScrollType = SB_HORZ; - nScrollCode = SB_PAGERIGHT; - break; - } - - - default : bHandled = FALSE; return 0; - } - - DoScroll(nScrollType, nScrollCode, 0); - return 0; -} ////////////////////////////////////////////////////////////////////////////// @@ -941,107 +949,103 @@ LRESULT ConsoleView::OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWnd void ConsoleView::GetRect(CRect& clientRect) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + RECT rect; + GetWindowRect(&rect); - 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; + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; - if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; - if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; -} + 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); +} -bool ConsoleView::GetMaxRect(CRect& maxClientRect) +void ConsoleView::GetRectMax(CRect& clientMaxRect) { - if (m_bInitializing) return false; + 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; - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + if (m_bShowVScroll) clientMaxRect.right += m_nVScrollWidth; + if (m_bShowHScroll) clientMaxRect.bottom += m_nHScrollWidth; +} - // 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; +////////////////////////////////////////////////////////////////////////////// - CWindow desktopWindow(::GetDesktopWindow()); - CRect rectDesktop; - bool bRecalc = false; - desktopWindow.GetWindowRect(rectDesktop); +////////////////////////////////////////////////////////////////////////////// +//long l2 = 0; +void ConsoleView::AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge) +{ + GetWindowRect(&clientRect); - if (rectDesktop.Width() < maxClientRect.Width()) - { - m_consoleHandler.GetConsoleParams()->dwMaxColumns = (rectDesktop.Width() - 2*stylesSettings.dwInsideBorder) / m_nCharWidth; - bRecalc = true; - } + //TRACE(L"========AdjustRectAndResize (%d)=================================\n", ::InterlockedIncrement(&l2)); + //TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); - if (rectDesktop.Height() < maxClientRect.Height()) - { - m_consoleHandler.GetConsoleParams()->dwMaxRows = (rectDesktop.Height() - 2*stylesSettings.dwInsideBorder) / m_nCharHeight; - bRecalc = true; - } + LONG width = clientRect.right - clientRect.left; + LONG height = clientRect.bottom - clientRect.top; - if (bRecalc) - { - maxClientRect.right = m_consoleHandler.GetConsoleParams()->dwMaxColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; - maxClientRect.bottom= m_consoleHandler.GetConsoleParams()->dwMaxRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; - } + // exclude scrollbars from row/col calculation + if (m_bShowVScroll) width -= m_nVScrollWidth; + if (m_bShowHScroll) height -= m_nHScrollWidth; - if (m_bShowVScroll) maxClientRect.right += m_nVScrollWidth; - if (m_bShowHScroll) maxClientRect.bottom+= m_nHScrollWidth; + // exclude inside borders from row/col calculation + width -= (m_nVInsideBorder * 2); + height -= (m_nHInsideBorder * 2); - return true; -} + //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; -void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bGetClientRect) -{ - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + //TRACE(L"dwMaxColumns: %i dwMaxRows: %i\n", dwMaxColumns, dwMaxRows); - if (bGetClientRect) GetWindowRect(&clientRect); -/* - TRACE(L"================================================================\n"); - TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); -*/ + if( dwColumns > dwMaxColumns ) + dwColumns = dwMaxColumns; + if( dwRows > dwMaxRows ) + dwRows = dwMaxRows; - // exclude scrollbars from row/col calculation - if (m_bShowVScroll) clientRect.right -= m_nVScrollWidth; - if (m_bShowHScroll) clientRect.bottom -= m_nHScrollWidth; + //TRACE(L"dwColumns: %i dwRows: %i\n", dwColumns, dwRows); - // 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 + m_nVInsideBorder * 2; + clientRect.bottom = clientRect.top + dwRows * m_nCharHeight + m_nHInsideBorder * 2; - 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; - // 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); - 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"); -*/ + RecreateOffscreenBuffers(as); + Repaint(true); - m_consoleHandler.GetNewConsoleSize().SetReqEvent(); + m_consoleHandler.GetNewConsoleSize().SetReqEvent(); } ////////////////////////////////////////////////////////////////////////////// @@ -1080,13 +1084,25 @@ void ConsoleView::SetAppActiveStatus(bool bAppActive) ////////////////////////////////////////////////////////////////////////////// -void ConsoleView::RecreateOffscreenBuffers() +void ConsoleView::RecreateFont() { - if (!m_fontText.IsNull()) m_fontText.DeleteObject(); - if (!m_backgroundBrush.IsNull())m_backgroundBrush.DeleteObject(); - if (!m_bmpOffscreen.IsNull()) m_bmpOffscreen.DeleteObject(); - if (!m_bmpText.IsNull()) m_bmpText.DeleteObject(); - CreateOffscreenBuffers(); + if (!m_fontText.IsNull()) m_fontText.DeleteObject(); + if (!CreateFont(g_settingsHandler->GetAppearanceSettings().fontSettings.strName)) + { + CreateFont(wstring(L"Courier New")); + } +} + +void ConsoleView::RecreateOffscreenBuffers(ADJUSTSIZE as) +{ + 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; } ////////////////////////////////////////////////////////////////////////////// @@ -1096,6 +1112,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) { @@ -1158,7 +1175,19 @@ void ConsoleView::SetActive(bool bActive) void ConsoleView::SetTitle(const CString& strTitle) { - m_strTitle = strTitle; + CString title(strTitle); + + if (m_strUser.GetLength() > 0) + if (m_boolNetOnly) + { + title.Format(L"{%s} %s", m_strUser, strTitle); + } + else + { + title.Format(L"[%s] %s", m_strUser, strTitle); + } + + m_strTitle = title; SetWindowText(m_strTitle); } @@ -1174,16 +1203,38 @@ CString ConsoleView::GetConsoleCommand() consoleWnd.GetWindowText(strConsoleTitle); + int nPos = strConsoleTitle.Find(L"Console2 command window"); + + if (nPos == -1) + { + return CString(L" - ") + strConsoleTitle; + } + else + { + return CString(); + } + +#if 0 int nPos = strConsoleTitle.Find(L'-'); if (nPos == -1) { - return CString(L""); + nPos = strConsoleTitle.Find(L"Console2 command window"); + + if (nPos == -1) + { + return CString(L" - ") + strConsoleTitle; + } + else + { + return CString(); + } } else { return strConsoleTitle.Right(strConsoleTitle.GetLength() - nPos + 1); } +#endif } ///////////////////////////////////////////////////////////////////////////// @@ -1201,6 +1252,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)); @@ -1219,6 +1275,24 @@ void ConsoleView::Copy(const CPoint* pPoint /* = NULL */) ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +void ConsoleView::SelectAll() +{ + m_selectionHandler->SelectAll(); + + // copy on select + if (g_settingsHandler->GetBehaviorSettings().copyPasteSettings.bCopyOnSelect) + { + Copy(NULL); + } + + BitBltOffscreen(); +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// void ConsoleView::ClearSelection() @@ -1240,23 +1314,8 @@ 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); - -/* - 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"); - */ } ////////////////////////////////////////////////////////////////////////////// @@ -1269,11 +1328,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; @@ -1298,30 +1357,39 @@ void ConsoleView::DumpBuffer() 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); + 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) { - 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; + + if (bResize) wParam |= UPDATE_CONSOLE_RESIZE; + + if (consoleInfo->textChanged) + { + wParam |= UPDATE_CONSOLE_TEXT_CHANGED; + consoleInfo->textChanged = false; } - PostMessage(UM_UPDATE_CONSOLE_VIEW, bResize ? 1 : 0); + PostMessage(UM_UPDATE_CONSOLE_VIEW, wParam); } ////////////////////////////////////////////////////////////////////////////// @@ -1343,13 +1411,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; @@ -1379,13 +1440,13 @@ 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 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); @@ -1400,14 +1461,18 @@ void ConsoleView::CreateOffscreenBuffers() // create selection handler m_selectionHandler.reset(new SelectionHandler( m_hWnd, +#ifndef _USE_AERO dcWindow, rectWindowMax, +#endif //!_USE_AERO m_consoleHandler, 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); @@ -1419,7 +1484,8 @@ 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), + this); } ////////////////////////////////////////////////////////////////////////////// @@ -1444,22 +1510,24 @@ bool ConsoleView::CreateFont(const wstring& strFontName) { if (!m_fontText.IsNull()) return true;// m_fontText.DeleteObject(); + CDC dcText(::CreateCompatibleDC(NULL)); + 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 , 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, @@ -1471,19 +1539,24 @@ bool ConsoleView::CreateFont(const wstring& strFontName) TEXTMETRIC textMetric; - m_dcText.SelectFont(m_fontText); - m_dcText.GetTextMetrics(&textMetric); - - if (textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) + dcText.SelectFont(m_fontText); + if( !dcText.GetTextMetrics(&textMetric) || (textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) ) { + TRACE(L"/!\\ can't use %s font\n", strFontName.c_str()); if (!m_fontText.IsNull()) m_fontText.DeleteObject(); return false; } // fixed pitch font (TMPF_FIXED_PITCH is cleared!!!) - m_nCharWidth = textMetric.tmAveCharWidth; + m_nCharWidth = textMetric.tmAveCharWidth; m_nCharHeight = textMetric.tmHeight; + m_nVScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL); + m_nHScrollWidth = ::GetSystemMetrics(SM_CXHSCROLL); + + m_nVInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; + m_nHInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; + return true; } @@ -1496,8 +1569,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) @@ -1511,8 +1584,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); @@ -1522,28 +1595,32 @@ void ConsoleView::InitializeScrollbars() if (m_appearanceSettings.controlsSettings.bShowScrollbars && (consoleParams->dwBufferRows > consoleParams->dwRows)) { + m_dwVScrollMax = max(m_dwVScrollMax, consoleParams->dwRows - 1); + // set vertical scrollbar stuff SCROLLINFO si ; - si.cbSize = sizeof(SCROLLINFO) ; - si.fMask = SIF_PAGE | SIF_RANGE ; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nPage = consoleParams->dwRows; - si.nMax = consoleParams->dwBufferRows - 1; + si.nMax = m_dwVScrollMax; /*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); } @@ -1560,9 +1637,9 @@ void ConsoleView::DoScroll(int nType, int nScrollCode, int nThumbPos) int nDelta = 0; ScrollSettings& scrollSettings = g_settingsHandler->GetBehaviorSettings().scrollSettings; - + switch(nScrollCode) - { + { case SB_PAGEUP: /* SB_PAGELEFT */ if (scrollSettings.dwPageScrollRows > 0) @@ -1573,8 +1650,8 @@ 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; - + break; + case SB_PAGEDOWN: /* SB_PAGERIGHT */ if (scrollSettings.dwPageScrollRows > 0) { @@ -1584,28 +1661,35 @@ 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; - + break; + case SB_LINEUP: /* SB_LINELEFT */ - nDelta = -1; - break; - + nDelta = -1; + break; + case SB_LINEDOWN: /* SB_LINERIGHT */ - nDelta = 1; - break; - + nDelta = 1; + break; + case SB_THUMBTRACK: case SB_THUMBPOSITION: - nDelta = nThumbPos - nCurrentPos; + nDelta = nThumbPos - nCurrentPos; break; - + case SB_ENDSCROLL: return; - - default: + + default: return; } - + + if( nType == SB_VERT ) + { + int nVScrollMaxTop = static_cast(m_dwVScrollMax - m_consoleHandler.GetConsoleParams()->dwRows + 1); + if( nCurrentPos + nDelta > nVScrollMaxTop ) + nDelta = nVScrollMaxTop - nCurrentPos; + } + if (nDelta != 0) { SharedMemory& newScrollPos = m_consoleHandler.GetNewScrollPos(); @@ -1632,9 +1716,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) { @@ -1658,16 +1742,16 @@ 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); } +#ifdef _USE_AERO + m_mainFrame.m_taskBarList.UpdateTabTitle(this); +#endif + m_mainFrame.PostMessage( - UM_UPDATE_TITLES, - reinterpret_cast(m_hWnd), + UM_UPDATE_TITLES, + reinterpret_cast(m_hwndTabView), 0); } @@ -1686,53 +1770,89 @@ 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) { +#ifdef _USE_AERO + // set transparency + TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; + if (transparencySettings.transType == transGlass) + { + Gdiplus::Graphics gr(dc); + + COLORREF backgroundColor = m_tabData->crBackgroundColor; + + gr.Clear( + Gdiplus::Color( + this->m_mainFrame.GetAppActiveStatus()? transparencySettings.byActiveAlpha : transparencySettings.byInactiveAlpha, + GetRValue(backgroundColor), + GetGValue(backgroundColor), + GetBValue(backgroundColor))); + } + else + { + dc.FillRect(&bitmapRect, m_backgroundBrush); + } +#else dc.FillRect(&bitmapRect, m_backgroundBrush); +#endif } 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); - g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); + //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); 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); } } - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); - DWORD dwX = stylesSettings.dwInsideBorder; - DWORD dwY = stylesSettings.dwInsideBorder; + for (DWORD i = 0; i < m_dwScreenRows; ++i) + { + this->RowTextOut(dc, i); + } + +#if 0 + DWORD dwX = m_nVInsideBorder; + DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; WORD attrBG; @@ -1747,10 +1867,10 @@ 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 = stylesSettings.dwInsideBorder; - dwY = i*m_nCharHeight + stylesSettings.dwInsideBorder; + dwX = m_nVInsideBorder; + dwY = i*m_nCharHeight + m_nHInsideBorder; nBkMode = TRANSPARENT; crBkColor = RGB(0, 0, 0); @@ -1762,9 +1882,9 @@ void ConsoleView::RepaintText(CDC& dc) attrBG = (m_screenBuffer[dwOffset].charInfo.Attributes & 0xFF) >> 4; // here we decide how to paint text over the background - if (m_consoleSettings.consoleColors[attrBG] == RGB(0, 0, 0)) + if (/*m_consoleSettings.consoleColors[attrBG] == RGB(0, 0, 0)*/attrBG == 0) { - nBkMode = TRANSPARENT; + nBkMode = TRANSPARENT; } else { @@ -1784,7 +1904,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) { @@ -1795,7 +1915,7 @@ void ConsoleView::RepaintText(CDC& dc) attrBG = (m_screenBuffer[dwOffset].charInfo.Attributes & 0xFF) >> 4; - if (m_consoleSettings.consoleColors[attrBG] == RGB(0, 0, 0)) + if (/*m_consoleSettings.consoleColors[attrBG] == RGB(0, 0, 0)*/attrBG == 0) { if (nBkMode != TRANSPARENT) { @@ -1827,7 +1947,7 @@ void ConsoleView::RepaintText(CDC& dc) { CRect textOutRect(dwX, dwY, dwX+m_nCharWidth*nCharWidths, dwY+m_nCharHeight); - dc.ExtTextOut(dwX, dwY, 0, &textOutRect, strText.c_str(), static_cast(strText.length()), NULL); + dc.ExtTextOut(dwX, dwY, ETO_CLIPPED, &textOutRect, strText.c_str(), static_cast(strText.length()), NULL); dwX += static_cast(nCharWidths * m_nCharWidth); dc.SetBkMode(nBkMode); @@ -1850,9 +1970,10 @@ void ConsoleView::RepaintText(CDC& dc) if (strText.length() > 0) { CRect textOutRect(dwX, dwY, dwX+m_nCharWidth*nCharWidths, dwY+m_nCharHeight); - dc.ExtTextOut(dwX, dwY, 0, &textOutRect, strText.c_str(), static_cast(strText.length()), NULL); + dc.ExtTextOut(dwX, dwY, ETO_CLIPPED, &textOutRect, strText.c_str(), static_cast(strText.length()), NULL); } } +#endif } ///////////////////////////////////////////////////////////////////////////// @@ -1862,96 +1983,288 @@ 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 dwOffset = 0; - - WORD attrBG; - - MutexLock bufferLock(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) - { - dwX = stylesSettings.dwInsideBorder; - dwY = i*m_nCharHeight + stylesSettings.dwInsideBorder; - - for (DWORD j = 0; j < m_consoleHandler.GetConsoleParams()->dwColumns; ++j, ++dwOffset, dwX += m_nCharWidth) - { - if (m_screenBuffer[dwOffset].changed) - { - m_screenBuffer[dwOffset].changed = false; - - if (m_screenBuffer[dwOffset].charInfo.Attributes & COMMON_LVB_TRAILING_BYTE) continue; - - CRect rect; - rect.top = dwY; - rect.left = dwX; - 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); - } - else - { - 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), - SRCCOPY); - } - else - { - dc.BitBlt( - rect.left, - rect.top, - rect.Width(), - rect.Height(), - m_background->dcImage, - rect.left, - rect.top, - SRCCOPY); - } - } + //TRACE(L"ConsoleView::RepaintTextChanges\n"); + DWORD dwY = m_nHInsideBorder; + DWORD dwOffset = 0; + + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + + 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) + { + //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) + { + DWORD dwX = m_nVInsideBorder; + + bool rowHasChanged = false; + + for (DWORD j = 0; j < m_dwScreenColumns; ++j, ++dwOffset, dwX += m_nCharWidth) + { + if (m_screenBuffer[dwOffset].changed) + { + rowHasChanged = true; + } + } + + if( rowHasChanged ) + { + CRect rect; + rect.top = dwY; + rect.left = m_nVInsideBorder; + rect.bottom = dwY + m_nCharHeight; + rect.right = dwX; + + if (m_tabData->backgroundImageType == bktypeNone) + { + dc.FillRect(&rect, m_backgroundBrush); +#if _USE_AERO + // set transparency + TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; + if (transparencySettings.transType == transGlass) + { + Gdiplus::Graphics gr(dc); + + gr.SetClip( + Gdiplus::Rect( + rect.left, rect.top, + rect.Width(), rect.Height()), + Gdiplus::CombineModeReplace); + + COLORREF backgroundColor = m_tabData->crBackgroundColor; + + gr.Clear( + Gdiplus::Color( + this->m_mainFrame.GetAppActiveStatus()? transparencySettings.byActiveAlpha : transparencySettings.byInactiveAlpha, + GetRValue(backgroundColor), + GetGValue(backgroundColor), + GetBValue(backgroundColor))); + } +#endif + } + else + { + if (m_tabData->imageData.bRelative) + { + dc.BitBlt( + 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.Width(), + rect.Height(), + m_background->dcImage, + rect.left + pointView.x - pointTab.x, + rect.top + pointView.y - pointTab.y, + SRCCOPY); + } + } + + this->RowTextOut(dc, i); + } + } +} - attrBG = (m_screenBuffer[dwOffset].charInfo.Attributes & 0xFF) >> 4; - // here we decide how to paint text over the background - if (m_consoleSettings.consoleColors[attrBG] == RGB(0, 0, 0)) - { - dc.SetBkMode(TRANSPARENT); - } - else - { - dc.SetBkMode(OPAQUE); - dc.SetBkColor(m_consoleSettings.consoleColors[attrBG]); - } - - dc.SetBkColor(m_consoleSettings.consoleColors[attrBG]); - dc.SetTextColor(m_appearanceSettings.fontSettings.bUseColor ? m_appearanceSettings.fontSettings.crFontColor : m_consoleSettings.consoleColors[m_screenBuffer[dwOffset].charInfo.Attributes & 0xF]); - - dc.ExtTextOut(dwX, dwY, ETO_CLIPPED, &rect, &(m_screenBuffer[dwOffset].charInfo.Char.UnicodeChar), 1, NULL); - } - } - } +void ConsoleView::RowTextOut(CDC& dc, DWORD dwRow) +{ + //TRACE(L"ConsoleView::RepaintRow %lu\n", dwRow); + DWORD dwX = m_nVInsideBorder; + DWORD dwY = m_nHInsideBorder + m_nCharHeight * dwRow; + DWORD dwOffset = m_dwScreenColumns * dwRow; + +#ifdef _USE_AERO + Gdiplus::Graphics gr(dc); +#endif //_USE_AERO + + std::unique_ptr dxWidths(new INT[m_dwScreenColumns]); + for(size_t i = 0; i < m_dwScreenColumns; ++i) + dxWidths[i] = m_nCharWidth; + + // first pass : text background color + WORD attrBG = 0; + DWORD dwBGWidth = 0; + + for (DWORD j = 0; j < m_dwScreenColumns; ++j, ++dwOffset) + { + // reset change state + m_screenBuffer[dwOffset].changed = false; + + // compare background color + WORD attrBG2 = (m_screenBuffer[dwOffset].charInfo.Attributes & 0xFF) >> 4; + if( dwBGWidth == 0 ) + { + attrBG = attrBG2; + dwBGWidth = m_nCharWidth; + } + else + { + if( attrBG == attrBG2 ) + { + dwBGWidth += m_nCharWidth; + } + else + { + // draw background and reset + + if (attrBG != 0) + { +#ifdef _USE_AERO + COLORREF backgroundColor = m_consoleSettings.consoleColors[attrBG]; + Gdiplus::SolidBrush backgroundBrush( + Gdiplus::Color( + m_consoleSettings.backgroundTextOpacity, + GetRValue(backgroundColor), + GetGValue(backgroundColor), + GetBValue(backgroundColor))); + + gr.FillRectangle( + &backgroundBrush, + dwX, dwY, + dwBGWidth, m_nCharHeight); +#else //_USE_AERO + CBrush backgroundBrush; + backgroundBrush.CreateSolidBrush(m_consoleSettings.consoleColors[attrBG]); + + CRect rect; + rect.top = dwY; + rect.left = dwX; + rect.bottom = dwY + m_nCharHeight; + rect.right = dwX + dwBGWidth; + + dc.FillRect(&rect, (HBRUSH)backgroundBrush); +#endif //_USE_AERO + } + + attrBG = attrBG2; + dwX += dwBGWidth; + dwBGWidth = m_nCharWidth; + } + } + } + + if( dwBGWidth > 0 ) + { + if (attrBG != 0) + { +#ifdef _USE_AERO + COLORREF backgroundColor = m_consoleSettings.consoleColors[attrBG]; + Gdiplus::SolidBrush backgroundBrush( + Gdiplus::Color( + m_consoleSettings.backgroundTextOpacity, + GetRValue(backgroundColor), + GetGValue(backgroundColor), + GetBValue(backgroundColor))); + + gr.FillRectangle( + &backgroundBrush, + dwX, dwY, + dwBGWidth, m_nCharHeight); +#else //_USE_AERO + CBrush backgroundBrush; + backgroundBrush.CreateSolidBrush(m_consoleSettings.consoleColors[attrBG]); + + CRect rect; + rect.top = dwY; + rect.left = dwX; + rect.bottom = dwY + m_nCharHeight; + rect.right = dwX + dwBGWidth; + dc.FillRect(&rect, backgroundBrush); +#endif //_USE_AERO + + dwX += dwBGWidth; + } + } + + // second pass : text + dwX = m_nVInsideBorder; + dwOffset = m_dwScreenColumns * dwRow; + + wstring strText(L""); + COLORREF colorFG = 0; + DWORD dwFGWidth = 0; + + for (DWORD j = 0; j < m_dwScreenColumns; ++j, ++dwOffset) + { + if (m_screenBuffer[dwOffset].charInfo.Attributes & COMMON_LVB_TRAILING_BYTE) continue; + + + // compare foreground color + COLORREF colorFG2 = m_appearanceSettings.fontSettings.bUseColor ? m_appearanceSettings.fontSettings.crFontColor : m_consoleSettings.consoleColors[m_screenBuffer[dwOffset].charInfo.Attributes & 0xF]; + if( dwFGWidth == 0 ) + { + colorFG = colorFG2; + dwFGWidth = m_nCharWidth; + } + else + { + if( colorFG == colorFG2 ) + { + dwFGWidth += m_nCharWidth; + } + else + { + // draw text and reset + + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(colorFG); + + CRect rect; + rect.top = dwY; + rect.left = dwX; + rect.bottom = dwY + m_nCharHeight; + // we add the space of the next char + // in italic a part of the previous char is drawn in the following char space + rect.right = dwX + dwFGWidth + m_nCharWidth; + + dc.ExtTextOut(dwX, dwY, ETO_CLIPPED, &rect, strText.c_str(), static_cast(strText.length()), dxWidths.get()); + + strText.clear(); + colorFG = colorFG2; + dwX += dwFGWidth; + dwFGWidth = m_nCharWidth; + } + } + + strText += m_screenBuffer[dwOffset].charInfo.Char.UnicodeChar; + } + + if( dwBGWidth > 0 ) + { + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(colorFG); + + CRect rect; + rect.top = dwY; + rect.left = dwX; + rect.bottom = dwY + m_nCharHeight; + rect.right = dwX + dwFGWidth; + + dc.ExtTextOut(dwX, dwY, ETO_CLIPPED, &rect, strText.c_str(), static_cast(strText.length()), dxWidths.get()); + } } ///////////////////////////////////////////////////////////////////////////// @@ -1962,20 +2275,19 @@ void ConsoleView::RepaintTextChanges(CDC& dc) void ConsoleView::BitBltOffscreen(bool bOnlyCursor /*= false*/) { CRect rectBlit; - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; 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(); + 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 + 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 { @@ -2015,30 +2327,34 @@ 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(); - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); // 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 + 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, - rectCursor.left, + m_dcOffscreen, + rectCursor.left, rectCursor.top); } } // blit selection +#ifdef _USE_AERO + m_selectionHandler->Draw(m_dcOffscreen); + m_mainFrame.m_taskBarList.RefreshTab(this); +#else //_USE_AERO m_selectionHandler->BitBlt(m_dcOffscreen); +#endif //_USE_AERO } ///////////////////////////////////////////////////////////////////////////// @@ -2048,134 +2364,42 @@ 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]; + SharedMemory& textInfo = m_consoleHandler.GetTextInfo(); - 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(); - - { - SharedMemoryLock memLock(pasteInfo); + SharedMemoryLock memLock(textInfo); 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); return; } - pasteInfo = reinterpret_cast(pRemoteMemory); - pasteInfo.SetReqEvent(); + textInfo->mem = reinterpret_cast(pRemoteMemory); + textInfo.SetReqEvent(); } - ::WaitForSingleObject(pasteInfo.GetRespEvent(), INFINITE); + ::WaitForSingleObject(textInfo.GetRespEvent(), INFINITE); } ///////////////////////////////////////////////////////////////////////////// @@ -2191,28 +2415,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; } } @@ -2364,25 +2588,30 @@ void ConsoleView::ForwardMouseClick(UINT uMsg, WPARAM wParam, const CPoint& poin ///////////////////////////////////////////////////////////////////////////// -COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) +COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint, bool bStartSelection) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - 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; 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) { - 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; @@ -2396,3 +2625,139 @@ COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) ///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void ConsoleView::RedrawCharOnCursor(CDC& dc) +{ + CRect rectCursor(0, 0, 0, 0); + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); + + rectCursor = m_cursor->GetCursorRect(); + 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; + + CBrush brush(::CreateSolidBrush(m_tabData->crCursorColor)); + dc.FillRect(rectCursor, brush); + + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + DWORD dwOffset = + (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_dwScreenColumns + + (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left); + + dc.SetBkMode(TRANSPARENT); + dc.SelectFont(m_fontText); + + COLORREF colorBG; + + if( g_settingsHandler->GetAppearanceSettings().fontSettings.bItalic && + (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) > 0 ) + { + colorBG = m_consoleSettings.consoleColors[(m_screenBuffer[dwOffset - 1].charInfo.Attributes & 0xF0) >> 4]; + + dc.SetTextColor(colorBG); + dc.ExtTextOut( + rectCursor.left - m_nCharWidth, rectCursor.top, + ETO_CLIPPED, + &rectCursor, + &m_screenBuffer[dwOffset - 1].charInfo.Char.UnicodeChar, 1, + nullptr); + } + + colorBG = m_consoleSettings.consoleColors[(m_screenBuffer[dwOffset].charInfo.Attributes & 0xF0) >> 4]; + + dc.SetTextColor(colorBG); + dc.ExtTextOut( + rectCursor.left, rectCursor.top, + ETO_CLIPPED, + &rectCursor, + &m_screenBuffer[dwOffset].charInfo.Char.UnicodeChar, 1, + nullptr); +} + + +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// + +HBITMAP ConsoleView::GetThumbnail(int nMaxWidth, int nMaxHeight) +{ + TRACE(L"******** ConsoleView::GetThumbnail called\n"); + + CRect clientRect; + clientRect.left = m_nVInsideBorder; + clientRect.top = m_nHInsideBorder; + clientRect.right = m_consoleHandler.GetConsoleParams()->dwColumns * m_nCharWidth + m_nVInsideBorder; + clientRect.bottom = m_consoleHandler.GetConsoleParams()->dwRows * m_nCharHeight + m_nHInsideBorder; + + if( clientRect.Width() == 0 || clientRect.Height() == 0 ) + return nullptr; + + int nWidth = nMaxWidth; + int nHeight = nMaxHeight; + + /* If the window fits in the thumbnail */ + if( clientRect.Width() <= nMaxWidth && clientRect.Height() <= nMaxHeight ) + { + nWidth = clientRect.Width(); + nHeight = clientRect.Height(); + } + else + { + /* If the current height of the window + is less than the width, we'll create a thumbnail + of maximum width; else maximum height. */ + + double dXRatio = static_cast(clientRect.Width ()) / static_cast(nWidth ); + double dYRatio = static_cast(clientRect.Height()) / static_cast(nHeight); + + if( dXRatio > dYRatio ) + { + nHeight = ::MulDiv(nWidth , clientRect.Height(), clientRect.Width ()); + } + else + { + nWidth = ::MulDiv(nHeight, clientRect.Width (), clientRect.Height()); + } + } + + /* Thumbnail bitmap. */ + CBitmap bmpThumbnail; + Helpers::CreateBitmap(m_dcOffscreen, nWidth, nHeight, bmpThumbnail); + + CDC dcThumbnail; + dcThumbnail.CreateCompatibleDC(m_dcOffscreen); + + /* Finally, shrink the full-scale bitmap down into a thumbnail. */ + dcThumbnail.SelectBitmap(bmpThumbnail); + dcThumbnail.SetStretchBltMode(HALFTONE); + dcThumbnail.SetBrushOrg(0, 0); + dcThumbnail.StretchBlt(0, 0, nWidth, nHeight, m_dcOffscreen, clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(), SRCCOPY); + + return bmpThumbnail.Detach(); +} + +HBITMAP ConsoleView::GetLivePreview(POINT& ptClient) +{ + POINT ptMainFrameClient; + m_mainFrame.ClientToScreen(&ptMainFrameClient); + this->ClientToScreen(&ptClient); + ptClient.x -= ptMainFrameClient.x; + ptClient.y -= ptMainFrameClient.y; + + return m_bmpOffscreen.m_hBitmap; +} + +void ConsoleView::Activate(void) +{ + /* Restore the main window if necessary, and switch + to the actual tab. */ + if( this->m_mainFrame.IsIconic() ) + { + this->m_mainFrame.ShowWindow(SW_RESTORE); + } + this->m_mainFrame.ActivateApp(this->m_hwndTabView, this->m_hWnd); +} \ No newline at end of file diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index a4bfdf6e..7a29202f 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -23,13 +23,14 @@ class MainFrame; class ConsoleView : public CWindowImpl > + , public CursorCharDrawer { public: // DECLARE_WND_CLASS(NULL) 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, std::shared_ptr tabData, const CString& strTitle, DWORD dwRows, DWORD dwColumns, const wstring& strCmdLineInitialDir = wstring(L""), const wstring& strCmdLineInitialCmd = wstring(L"")); ~ConsoleView(); BOOL PreTranslateMessage(MSG* pMsg); @@ -48,7 +49,7 @@ class ConsoleView MESSAGE_HANDLER(WM_SYSCHAR, OnConsoleFwdMsg) MESSAGE_HANDLER(WM_DEADCHAR, OnConsoleFwdMsg) MESSAGE_HANDLER(WM_SYSDEADCHAR, OnConsoleFwdMsg) - MESSAGE_HANDLER(WM_MOUSEWHEEL, OnConsoleFwdMsg) + MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) MESSAGE_HANDLER(WM_VSCROLL, OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, OnHScroll) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnMouseButton) @@ -67,7 +68,7 @@ class ConsoleView MESSAGE_HANDLER(WM_INPUTLANGCHANGE, OnInputLangChange) MESSAGE_HANDLER(WM_DROPFILES, OnDropFiles) MESSAGE_HANDLER(UM_UPDATE_CONSOLE_VIEW, OnUpdateConsoleView) - COMMAND_RANGE_HANDLER(ID_SCROLL_UP, ID_SCROLL_ALL_RIGHT, OnScrollCommand) + END_MSG_MAP() // Handler prototypes (uncomment arguments if needed): @@ -75,7 +76,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*/); @@ -84,9 +85,9 @@ class ConsoleView LRESULT OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/); LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); - LRESULT OnScrollCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled); LRESULT OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/); LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/); LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/); LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnInputLangChangeRequest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); @@ -94,52 +95,69 @@ class ConsoleView LRESULT OnDropFiles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); - LRESULT OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled); - + virtual void RedrawCharOnCursor(CDC& dc); - public: + HBITMAP GetThumbnail(int nMaxWidth, int nMaxHeight); + HBITMAP GetLivePreview(POINT& ptClient); void GetRect(CRect& clientRect); - bool GetMaxRect(CRect& maxClientRect); - void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bGetClientRect); + void GetRectMax(CRect& clientMaxRect); + void AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge); + CPoint GetCellSize() { return CPoint(m_nCharWidth, m_nCharHeight); }; ConsoleHandler& GetConsoleHandler() { return m_consoleHandler; } - shared_ptr GetTabData() { return m_tabData; } + std::shared_ptr GetTabData() { return m_tabData; } bool GetConsoleWindowVisible() const { return m_bConsoleWindowVisible; } void SetConsoleWindowVisible(bool bVisible); void SetAppActiveStatus(bool bAppActive); - void RecreateOffscreenBuffers(); + static void RecreateFont(); + void RecreateOffscreenBuffers(ADJUSTSIZE as); 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; } CString GetConsoleCommand(); - const CString& GetTitle() const { return m_strTitle; } - CIcon& GetIcon(bool bBigIcon = true) { return bBigIcon ? bigIcon : smallIcon; } void Copy(const CPoint* pPoint = NULL); + void SelectAll(); void ClearSelection(); void Paste(); + // sends text to the windows console + void SendTextToConsole(const wchar_t* pszText); + DWORD GetSelectionSize(void) const { return m_selectionHandler->GetSelectionSize(); } + + 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(); + const CString& GetExceptionMessage() const { return m_exceptionMessage; } + + inline bool IsGrouped() const { return m_boolIsGrouped; } + void Group(bool b) { m_boolIsGrouped = b; } + + void DoScroll(int nType, int nScrollCode, int nThumbPos); + + void Activate(void); + + void OnConsoleClose(); + private: void OnConsoleChange(bool bResize); - void OnConsoleClose(); void CreateOffscreenBuffers(); void CreateOffscreenBitmap(CDC& cdc, const CRect& rect, CBitmap& bitmap); - bool CreateFont(const wstring& strFontName); - - void DoScroll(int nType, int nScrollCode, int nThumbPos); + static bool CreateFont(const wstring& strFontName); DWORD GetBufferDifference(); @@ -147,25 +165,24 @@ class ConsoleView void RepaintText(CDC& dc); void RepaintTextChanges(CDC& dc); + void RowTextOut(CDC& dc, DWORD dwRow); void BitBltOffscreen(bool bOnlyCursor = false); void UpdateOffscreen(const CRect& rectBlit); - // sends text to the windows console - void SendTextToConsole(const wchar_t* pszText); - 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: MainFrame& m_mainFrame; + HWND m_hwndTabView; wstring m_strCmdLineInitialDir; - wstring m_strInitialCmd; - wstring m_strDbgCmdLine; + wstring m_strCmdLineInitialCmd; bool m_bInitializing; bool m_bResizing; @@ -174,57 +191,66 @@ class ConsoleView bool m_bNeedFullRepaint; bool m_bUseTextAlphaBlend; bool m_bConsoleWindowVisible; + bool m_boolIsGrouped; DWORD m_dwStartupRows; DWORD m_dwStartupColumns; + DWORD m_dwVScrollMax; + int m_nVWheelDelta; bool m_bShowVScroll; bool m_bShowHScroll; - int m_nVScrollWidth; - int m_nHScrollWidth; CString m_strTitle; - - CIcon bigIcon; - CIcon smallIcon; + CString m_strUser; + bool m_boolNetOnly; - ConsoleHandler m_consoleHandler; + ConsoleHandler m_consoleHandler; - shared_array m_screenBuffer; + std::unique_ptr m_screenBuffer; + DWORD m_dwScreenRows; + DWORD m_dwScreenColumns; ConsoleSettings& m_consoleSettings; AppearanceSettings& m_appearanceSettings; HotKeys& m_hotkeys; - shared_ptr m_tabData; - shared_ptr m_background; + std::shared_ptr m_tabData; + std::shared_ptr m_background; CBrush m_backgroundBrush; - shared_ptr m_cursor; - shared_ptr m_selectionHandler; + std::shared_ptr m_cursor; + std::shared_ptr m_selectionHandler; MouseSettings::Command m_mouseCommand; - Mutex m_bufferMutex; - 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: - 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/Cursors.cpp b/Console/Cursors.cpp index 5784a717..9f545dd3 100644 --- a/Console/Cursors.cpp +++ b/Console/Cursors.cpp @@ -44,9 +44,9 @@ wchar_t* Cursor::s_cursorNames[] = ////////////////////////////////////////////////////////////////////////////// -shared_ptr CursorFactory::CreateCursor(HWND hwndConsoleView, bool bAppActive, CursorStyle cursorStyle, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor) +std::shared_ptr CursorFactory::CreateCursor(HWND hwndConsoleView, bool bAppActive, CursorStyle cursorStyle, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor, CursorCharDrawer* pdrawer) { - shared_ptr newCursor; + std::shared_ptr newCursor; switch (cursorStyle) { @@ -55,7 +55,8 @@ shared_ptr CursorFactory::CreateCursor(HWND hwndConsoleView, bool bAppAc hwndConsoleView, dcConsoleView, rectCursor, - crCursorColor))); + crCursorColor, + pdrawer))); break; case cstyleBlock : @@ -172,8 +173,9 @@ shared_ptr CursorFactory::CreateCursor(HWND hwndConsoleView, bool bAppAc ////////////////////////////////////////////////////////////////////////////// // XTermCursor -XTermCursor::XTermCursor(HWND hwndConsoleView, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor) -: Cursor(hwndConsoleView, dcConsoleView, rectCursor, crCursorColor) +XTermCursor::XTermCursor(HWND hwndConsoleView, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor, CursorCharDrawer* pdrawer) + : Cursor(hwndConsoleView, dcConsoleView, rectCursor, crCursorColor) + , m_pdrawer(pdrawer) { } @@ -188,15 +190,9 @@ XTermCursor::~XTermCursor() void XTermCursor::Draw(bool bActive /* = true */) { - if (bActive) - { - m_dcCursor.FillRect(&m_rectCursor, m_paintBrush); - } - else - { - m_dcCursor.FillRect(&m_rectCursor, m_backgroundBrush); - m_dcCursor.FrameRect(&m_rectCursor, m_paintBrush); - } + m_dcCursor.FillRect(&m_rectCursor, m_backgroundBrush); + m_dcCursor.FrameRect(&m_rectCursor, m_paintBrush); + m_bActive = bActive; } ////////////////////////////////////////////////////////////////////////////// @@ -206,15 +202,24 @@ void XTermCursor::Draw(bool bActive /* = true */) void XTermCursor::BitBlt(CDC& offscreenDC, int x, int y) { - offscreenDC.BitBlt( - x, - y, - m_rectCursor.Width(), - m_rectCursor.Height(), - m_dcCursor, - 0, - 0, - SRCINVERT); + if( m_bActive ) + { + m_pdrawer->RedrawCharOnCursor(offscreenDC); + } + else + { + offscreenDC.TransparentBlt( + x, + y, + m_rectCursor.Width(), + m_rectCursor.Height(), + m_dcCursor, + 0, + 0, + m_rectCursor.Width(), + m_rectCursor.Height(), + RGB(0, 0, 0)); + } } ////////////////////////////////////////////////////////////////////////////// @@ -1066,8 +1071,6 @@ FadeBlockCursor::~FadeBlockCursor() void FadeBlockCursor::Draw(bool bActive /* = true */) { - m_dcCursor.FillRect(&m_rectCursor, m_paintBrush); -/* if (bActive) { m_dcCursor.FillRect(&m_rectCursor, m_paintBrush); @@ -1076,7 +1079,6 @@ void FadeBlockCursor::Draw(bool bActive /* = true */) { m_dcCursor.FillRect(&m_rectCursor, m_backgroundBrush); } -*/ } ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/Cursors.h b/Console/Cursors.h index 74a81f26..07218cdf 100644 --- a/Console/Cursors.h +++ b/Console/Cursors.h @@ -39,6 +39,17 @@ enum CursorStyle ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// +class CursorCharDrawer +{ +public: + CursorCharDrawer() {} + virtual ~CursorCharDrawer() {} + + virtual void RedrawCharOnCursor(CDC& dc) = 0; +}; + +////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// // A base class for all the cursors @@ -110,7 +121,7 @@ class Cursor class CursorFactory { public: - static shared_ptr CreateCursor(HWND hwndConsoleView, bool bAppActive, CursorStyle cursorStyle, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor); + static std::shared_ptr CreateCursor(HWND hwndConsoleView, bool bAppActive, CursorStyle cursorStyle, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor ,CursorCharDrawer*); }; ////////////////////////////////////////////////////////////////////////////// @@ -127,13 +138,16 @@ class CursorFactory class XTermCursor : public Cursor { public: - XTermCursor(HWND hwndConsoleView, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor); + XTermCursor(HWND hwndConsoleView, const CDC& dcConsoleView, const CRect& rectCursor, COLORREF crCursorColor, CursorCharDrawer*); ~XTermCursor(); void Draw(bool bActive = true); void BitBlt(CDC& offscreenDC, int x, int y); +private: + CursorCharDrawer* m_pdrawer; + bool m_bActive; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgCredentials.cpp b/Console/DlgCredentials.cpp new file mode 100644 index 00000000..3f5ead79 --- /dev/null +++ b/Console/DlgCredentials.cpp @@ -0,0 +1,86 @@ +#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); + GetDlgItem(IDC_PASSWORD).SetFocus(); + + 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; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +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..6b450cbe --- /dev/null +++ b/Console/DlgCredentials.h @@ -0,0 +1,61 @@ + +#pragma once + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +class DlgCredentials +#ifdef _USE_AERO + : public aero::CDialogImpl +#else + : public CDialogImpl +#endif + , 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) +#ifdef _USE_AERO + CHAIN_MSG_MAP(aero::CDialogImpl) +#endif + 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*/); + + public: + + const CString& GetUser() const { return m_user; } + const CString& GetPassword() const { return m_password; } + + private: + + CString m_user; + CString m_password; +}; + +////////////////////////////////////////////////////////////////////////////// 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/DlgSettingsAppearance.cpp b/Console/DlgSettingsAppearance.cpp index 377ec12f..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; } @@ -196,7 +175,6 @@ LRESULT DlgSettingsAppearance::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND / m_positionSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } @@ -239,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); } @@ -306,7 +284,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); @@ -317,33 +298,36 @@ 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(); + 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) + 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(); @@ -351,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 a456ea84..2559366d 100644 --- a/Console/DlgSettingsAppearance.h +++ b/Console/DlgSettingsAppearance.h @@ -22,24 +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() @@ -86,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/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..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(); @@ -97,7 +85,6 @@ LRESULT DlgSettingsBehavior::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*h m_behaviorSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } @@ -166,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..e164fc42 100644 --- a/Console/DlgSettingsBehavior.h +++ b/Console/DlgSettingsBehavior.h @@ -21,16 +21,17 @@ 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_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) 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 +63,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 609cef54..67eb0af7 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; @@ -82,6 +77,19 @@ LRESULT DlgSettingsConsole::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARA spin.SetAccel(1, &udAccel); spin.Detach(); + m_staticBGTextOpacity.Attach(GetDlgItem(IDC_BGTEXT_OPACITY_VAL)); + m_sliderBGTextOpacity.Attach(GetDlgItem(IDC_BGTEXT_OPACITY)); + m_sliderBGTextOpacity.SetRange(0, 255); + m_sliderBGTextOpacity.SetTicFreq(5); + m_sliderBGTextOpacity.SetPageSize(5); + m_sliderBGTextOpacity.SetPos(m_consoleSettings.backgroundTextOpacity); + UpdateSliderText(); + +#ifndef _USE_AERO + m_sliderBGTextOpacity.EnableWindow(FALSE); + m_staticBGTextOpacity.EnableWindow(FALSE); +#endif //_USE_AERO + DoDataExchange(DDX_LOAD); return TRUE; } @@ -136,13 +144,13 @@ LRESULT DlgSettingsConsole::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW { if (wID == IDOK) { - DoDataExchange(DDX_SAVE); + if (!DoDataExchange(DDX_SAVE)) return -1; + + m_consoleSettings.backgroundTextOpacity = static_cast(m_sliderBGTextOpacity.GetPos()); + 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(); @@ -150,7 +158,6 @@ LRESULT DlgSettingsConsole::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW m_consoleSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } @@ -203,6 +210,8 @@ LRESULT DlgSettingsConsole::OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*w LRESULT DlgSettingsConsole::OnClickedBtnResetColors(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ::CopyMemory(m_consoleSettings.consoleColors, m_consoleSettings.defaultConsoleColors, sizeof(m_consoleSettings.defaultConsoleColors)); + m_sliderBGTextOpacity.SetPos(255); + UpdateSliderText(); DoDataExchange(DDX_LOAD); Invalidate(); @@ -230,3 +239,62 @@ 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); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT DlgSettingsConsole::OnHScroll(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + UpdateSliderText(); + return 0; +} + +void DlgSettingsConsole::UpdateSliderText() +{ + CString strStaticText; + strStaticText.Format(L"%i", m_sliderBGTextOpacity.GetPos()); + + m_staticBGTextOpacity.SetWindowText(strStaticText); +} \ No newline at end of file diff --git a/Console/DlgSettingsConsole.h b/Console/DlgSettingsConsole.h index 39d245b2..c6b14735 100644 --- a/Console/DlgSettingsConsole.h +++ b/Console/DlgSettingsConsole.h @@ -23,14 +23,14 @@ 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(IDC_ROWS, m_consoleSettings.dwRows) - DDX_UINT(IDC_COLUMNS, m_consoleSettings.dwColumns) - 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_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_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() BEGIN_MSG_MAP(DlgSettingsConsole) @@ -42,6 +42,7 @@ class DlgSettingsConsole COMMAND_HANDLER(IDC_BTN_BROWSE_DIR, BN_CLICKED, OnClickedBtnBrowseDir) COMMAND_HANDLER(IDC_BTN_RESET_COLORS, BN_CLICKED, OnClickedBtnResetColors) COMMAND_RANGE_CODE_HANDLER(IDC_CLR_00, IDC_CLR_15, BN_CLICKED, OnClickedClrBtn) + MESSAGE_HANDLER(WM_HSCROLL, OnHScroll) END_MSG_MAP() // Handler prototypes (uncomment arguments if needed): @@ -59,15 +60,19 @@ class DlgSettingsConsole LRESULT OnClickedBtnResetColors(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedClrBtn(WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/); - private: + LRESULT OnHScroll(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + + virtual void OnDataValidateError(UINT nCtrlID, BOOL bSave, _XData& data); + private: ConsoleSettings m_consoleSettings; CString m_strShell; CString m_strInitialDir; - int m_nStartHidden; - int m_nSaveSize; + CTrackBarCtrl m_sliderBGTextOpacity; + CStatic m_staticBGTextOpacity; + void UpdateSliderText(); }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsHotkeys.cpp b/Console/DlgSettingsHotkeys.cpp index 9af479ac..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,21 +153,10 @@ 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); } - DestroyWindow(); return 0; } 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/DlgSettingsMain.cpp b/Console/DlgSettingsMain.cpp index ac00e47b..27ab2ecd 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) @@ -140,31 +149,31 @@ void DlgSettingsMain::CreateSettingsTree() // create console settings dialog - shared_ptr dlgConsole(dynamic_cast(new DlgSettingsConsole(m_pSettingsRoot))); + std::shared_ptr dlgConsole(dynamic_cast(new DlgSettingsConsole(m_pSettingsRoot))); AddDialogToTree(L"Console", dlgConsole, rect); // create appearance settings dialog - shared_ptr dlgAppearance(dynamic_cast(new DlgSettingsAppearance(m_pSettingsRoot))); + std::shared_ptr dlgAppearance(dynamic_cast(new DlgSettingsAppearance(m_pSettingsRoot))); HTREEITEM htiAppearance = AddDialogToTree(L"Appearance", dlgAppearance, rect); // create styles settings dialog - shared_ptr dlgStyles(dynamic_cast(new DlgSettingsStyles(m_pSettingsRoot))); + std::shared_ptr dlgStyles(dynamic_cast(new DlgSettingsStyles(m_pSettingsRoot))); AddDialogToTree(L"More...", dlgStyles, rect, htiAppearance); // create behavior settings dialog - shared_ptr dlgBehavior(dynamic_cast(new DlgSettingsBehavior(m_pSettingsRoot))); + std::shared_ptr dlgBehavior(dynamic_cast(new DlgSettingsBehavior(m_pSettingsRoot))); AddDialogToTree(L"Behavior", dlgBehavior, rect); // create hotkeys settings dialog - shared_ptr dlgHotKeys(dynamic_cast(new DlgSettingsHotkeys(m_pSettingsRoot))); + std::shared_ptr dlgHotKeys(dynamic_cast(new DlgSettingsHotkeys(m_pSettingsRoot))); HTREEITEM htiHotkeys = AddDialogToTree(L"Hotkeys", dlgHotKeys, rect); // create mouse commands settings dialog - shared_ptr dlgMouseCmds(dynamic_cast(new DlgSettingsMouse(m_pSettingsRoot))); + std::shared_ptr dlgMouseCmds(dynamic_cast(new DlgSettingsMouse(m_pSettingsRoot))); AddDialogToTree(L"Mouse", dlgMouseCmds, rect, htiHotkeys); // create tabs settings dialog - shared_ptr dlgTabs(dynamic_cast(new DlgSettingsTabs(m_pSettingsRoot))); + std::shared_ptr dlgTabs(dynamic_cast(new DlgSettingsTabs(m_pSettingsRoot))); AddDialogToTree(L"Tabs", dlgTabs, rect); m_treeCtrl.Expand(htiAppearance); @@ -177,7 +186,7 @@ void DlgSettingsMain::CreateSettingsTree() ////////////////////////////////////////////////////////////////////////////// -HTREEITEM DlgSettingsMain::AddDialogToTree(const wstring& strName, const shared_ptr& newDlg, CRect& rect, HTREEITEM htiParent /*= NULL*/) +HTREEITEM DlgSettingsMain::AddDialogToTree(const wstring& strName, const std::shared_ptr& newDlg, CRect& rect, HTREEITEM htiParent /*= NULL*/) { newDlg->Create(m_hWnd, rect); newDlg->SetWindowPos(HWND_TOP, rect.left, rect.top, 0, 0, SWP_NOSIZE); diff --git a/Console/DlgSettingsMain.h b/Console/DlgSettingsMain.h index fd0bbe17..0c1baa24 100644 --- a/Console/DlgSettingsMain.h +++ b/Console/DlgSettingsMain.h @@ -10,7 +10,7 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -typedef map > SettingsDlgsMap; +typedef map > SettingsDlgsMap; ////////////////////////////////////////////////////////////////////////////// @@ -42,7 +42,7 @@ class DlgSettingsMain private: void CreateSettingsTree(); - HTREEITEM AddDialogToTree(const wstring& strName, const shared_ptr& newDlg, CRect& rect, HTREEITEM htiParent = NULL); + HTREEITEM AddDialogToTree(const wstring& strName, const std::shared_ptr& newDlg, CRect& rect, HTREEITEM htiParent = NULL); private: 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 8177e58e..c5e1cfa7 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -35,20 +35,6 @@ 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_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; - CUpDownCtrl spin; spin.Attach(GetDlgItem(IDC_SPIN_INSIDE_BORDER)); @@ -56,12 +42,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); @@ -72,6 +58,7 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM UpdateSliderText(m_sliderInactiveAlpha.m_hWnd); EnableTabControls(); + EnableScrollbarControls(); EnableTransparencyControls(); DoDataExchange(DDX_LOAD); @@ -135,20 +122,6 @@ 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.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_transparencySettings.byActiveAlpha = static_cast(255 - m_sliderActiveAlpha.GetPos()); m_transparencySettings.byInactiveAlpha = static_cast(255 - m_sliderInactiveAlpha.GetPos()); @@ -165,7 +138,6 @@ LRESULT DlgSettingsStyles::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWn m_transparencySettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } @@ -181,6 +153,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; +} + ////////////////////////////////////////////////////////////////////////////// @@ -278,10 +257,22 @@ 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) + if (m_controlsSettings.bShowTabs) { GetDlgItem(IDC_CHECK_HIDE_SINGLE_TAB).EnableWindow(); + GetDlgItem(IDC_CHECK_TABS_ON_BOTTOM).EnableWindow(); + } +} + +void DlgSettingsStyles::EnableScrollbarControls() +{ + GetDlgItem(IDC_CHECK_FLAT_SCROLLBARS).EnableWindow(FALSE); + + if (m_controlsSettings.bShowScrollbars) + { + GetDlgItem(IDC_CHECK_FLAT_SCROLLBARS).EnableWindow(); } } @@ -301,7 +292,7 @@ void DlgSettingsStyles::EnableTransparencyControls() GetDlgItem(IDC_STATIC_KEY_COLOR).EnableWindow(FALSE); GetDlgItem(IDC_KEY_COLOR).EnableWindow(FALSE); - if (m_transparencySettings.transType == transAlpha) + if (m_transparencySettings.transType == transAlpha || m_transparencySettings.transType == transGlass) { GetDlgItem(IDC_STATIC_ACTIVE_WINDOW).EnableWindow(); GetDlgItem(IDC_STATIC_INACTIVE_WINDOW).EnableWindow(); diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index b12ab56c..86ddf31b 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -21,18 +21,21 @@ 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_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_stylesSettings.bQuake) + DDX_CHECK(IDC_CHECK_USE_JUMPLIST, m_stylesSettings.bJumplist) DDX_UINT(IDC_INSIDE_BORDER, m_stylesSettings.dwInsideBorder) DDX_RADIO(IDC_TRANSPARENCY_TYPE, reinterpret_cast(m_transparencySettings.transType)) END_DDX_MAP() @@ -44,9 +47,10 @@ 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_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): @@ -60,6 +64,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*/); @@ -68,6 +73,7 @@ class DlgSettingsStyles void UpdateSliderText(HWND hwnd); void EnableTabControls(); + void EnableScrollbarControls(); void EnableTransparencyControls(); private: @@ -78,22 +84,6 @@ 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_nShowScrollbars; - int m_nFlatScrollbars; - - int m_nShowCaption; - int m_nResizable; - int m_nTaskbarButton; - int m_nBorder; - int m_nTrayIcon; - - int m_nTransparencyType; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index 9857c507..7e1e27ae 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -35,17 +35,21 @@ 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(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())); } @@ -83,10 +87,25 @@ 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; } +LRESULT DlgSettingsTabs::OnTabIconChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + bool bUseDefaultIcon = m_page1.UseDefaultIcon() ? true : false; + wstring strIcon = m_page1.GetTabIcon(); + wstring strShell = m_page1.GetTabShell(); + + 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 ! + m_listCtrl.SetItem(m_listCtrl.GetSelectedIndex(), 0, LVIF_TEXT|LVIF_IMAGE, m_page1.GetTabTitle(), nIcon, 0, 0, 0); + + return 0; +} + ////////////////////////////////////////////////////////////////////////////// @@ -96,12 +115,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); @@ -114,7 +131,6 @@ LRESULT DlgSettingsTabs::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndC m_tabSettings.tabDataVector.end()); } - DestroyWindow(); return 0; } @@ -127,11 +143,11 @@ LRESULT DlgSettingsTabs::OnAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt { ConsoleSettings& consoleSettings = g_settingsHandler->GetConsoleSettings(); - shared_ptr tabData(new TabData(consoleSettings.strShell, consoleSettings.strInitialDir)); + std::shared_ptr tabData(new TabData(consoleSettings.strShell, consoleSettings.strInitialDir)); 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); @@ -143,6 +159,31 @@ 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(); + + std::shared_ptr tabData(new TabData(*(m_tabSettings.tabDataVector[nItem].get()))); + tabData->strTitle += L" (2)"; + + 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); + GetDlgItem(IDC_BTN_DELETE).EnableWindow(TRUE); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// LRESULT DlgSettingsTabs::OnUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) @@ -199,49 +240,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,41 +288,11 @@ 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) { - shared_ptr tmpData(*(m_tabSettings.tabDataVector.begin() + nItem)); + std::shared_ptr tmpData(*(m_tabSettings.tabDataVector.begin() + nItem)); m_listCtrl.DeleteItem(nItem); int nNewItem = m_listCtrl.InsertItem(nItem + nDirection, tmpData->strTitle.c_str()); diff --git a/Console/DlgSettingsTabs.h b/Console/DlgSettingsTabs.h index d97569b7..10f51917 100644 --- a/Console/DlgSettingsTabs.h +++ b/Console/DlgSettingsTabs.h @@ -28,10 +28,12 @@ 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) 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) @@ -47,9 +49,11 @@ 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*/); + 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*/); @@ -59,7 +63,6 @@ class DlgSettingsTabs private: - void SetTabData(TabData* pTabData); void MoveListItem(int nItem, int nDirection); private: @@ -67,6 +70,7 @@ class DlgSettingsTabs TabSettings m_tabSettings; CListViewCtrl m_listCtrl; + WTL::CImageList m_ImageList; CTabCtrl m_tabCtrl; PageSettingsTabs1 m_page1; diff --git a/Console/Helpers.cpp b/Console/Helpers.cpp index 7d9141bb..359a127b 100644 --- a/Console/Helpers.cpp +++ b/Console/Helpers.cpp @@ -13,8 +13,7 @@ wstring Helpers::GetModulePath(HINSTANCE hInstance) { - wchar_t szModulePath[MAX_PATH]; - ::ZeroMemory(szModulePath, sizeof(szModulePath)); + wchar_t szModulePath[MAX_PATH] = L""; ::GetModuleFileName(hInstance, szModulePath, MAX_PATH); @@ -26,16 +25,45 @@ wstring Helpers::GetModulePath(HINSTANCE hInstance) ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +wstring Helpers::GetModuleFileName(HINSTANCE hInstance) +{ + wchar_t szModulePath[MAX_PATH] = L""; + + ::GetModuleFileName(hInstance, szModulePath, MAX_PATH); + + wstring strPath(szModulePath); + + return strPath; +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// wstring Helpers::ExpandEnvironmentStrings(const wstring& str) { - shared_array szExpanded(new wchar_t[0x8000]); + wchar_t szExpanded[0x8000] = L""; + + ::ExpandEnvironmentStrings(str.c_str(), szExpanded, ARRAYSIZE(szExpanded)); + + return wstring(szExpanded); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +wstring Helpers::ExpandEnvironmentStringsForUser(HANDLE userToken, const wstring& str) +{ + wchar_t szExpanded[0x8000] = L""; - ::ZeroMemory(szExpanded.get(), 0x8000*sizeof(wchar_t)); - ::ExpandEnvironmentStrings(str.c_str(), szExpanded.get(), 0x8000); + ::ExpandEnvironmentStringsForUser(userToken, str.c_str(), szExpanded, ARRAYSIZE(szExpanded)); - return wstring(szExpanded.get()); + return wstring(szExpanded); } ////////////////////////////////////////////////////////////////////////////// @@ -137,3 +165,104 @@ HBITMAP Helpers::CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bi ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// + +wstring Helpers::LoadString(UINT uID) +{ + wchar_t str[0x800]; + + if( ::LoadString(::GetModuleHandle(NULL), uID, str, ARRAYSIZE(str)) ) + return wstring(str); + else + return wstring(L"LoadString failed"); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +HICON Helpers::LoadTabIcon(bool bBigIcon, bool bUseDefaultIcon, const wstring& strIcon, const wstring& strShell) +{ + if (bUseDefaultIcon) + { + if ( !strShell.empty() ) + { + wstring strCommandLine = Helpers::ExpandEnvironmentStrings(strShell); + int argc = 0; + std::unique_ptr 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; + } + } + } + } + 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( + NULL, + Helpers::ExpandEnvironmentStrings(strIcon).c_str(), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR | LR_LOADFROMFILE)); + } + } + } + + if ( bBigIcon ) + { + return static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_DEFAULTSIZE)); + } + else + { + 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..652970ce 100644 --- a/Console/Helpers.h +++ b/Console/Helpers.h @@ -15,8 +15,10 @@ class Helpers public: static wstring GetModulePath(HINSTANCE hInstance); + static wstring GetModuleFileName(HINSTANCE hInstance); static wstring ExpandEnvironmentStrings(const wstring& str); + static wstring ExpandEnvironmentStringsForUser(HANDLE userToken, const wstring& str); static void GetMonitorRect(HWND hWnd, CRect& rectMonitor); static void GetDesktopRect(HWND hWnd, CRect& rectDesktop); @@ -24,6 +26,9 @@ 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: static void GetMonitorRect(HMONITOR hMonitor, bool bIgnoreTaskbar, CRect& rectDesktop); @@ -111,7 +116,7 @@ class Mutex private: - shared_ptr m_mutex; + std::shared_ptr m_mutex; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/ImageHandler.cpp b/Console/ImageHandler.cpp index f1557086..c2ab34b0 100644 --- a/Console/ImageHandler.cpp +++ b/Console/ImageHandler.cpp @@ -3,6 +3,42 @@ ////////////////////////////////////////////////////////////////////////////// +bool ImageHandler::m_win8 = ImageHandler::CheckWin8(); + +bool ImageHandler::CheckWin8() +{ + OSVERSIONINFOEX osvi; + DWORDLONG dwlConditionMask = 0; + BYTE op = VER_GREATER_EQUAL; + + // Initialize the OSVERSIONINFOEX structure. + + ::ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = 6; + osvi.dwMinorVersion = 2; + + // Initialize the condition mask. + + VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op ); + VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op ); + + // Perform the test. + + if( ::VerifyVersionInfo( + &osvi, + VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + dwlConditionMask) ) + { + return true; + } + else + { + return false; + } +} + ImageHandler::ImageHandler() : m_images() { @@ -22,9 +58,52 @@ ImageHandler::~ImageHandler() ////////////////////////////////////////////////////////////////////////////// -shared_ptr ImageHandler::GetImage(const ImageData& imageData) +void ImageHandler::CalcRescale(DWORD& dwNewWidth, DWORD& dwNewHeight, std::shared_ptr& bkImage) +{ + switch( bkImage->imageData.imagePosition ) + { + case imagePositionFit: + { + double dXRatio = (double)dwNewWidth / (double)bkImage->originalImage->getWidth (); + double dYRatio = (double)dwNewHeight / (double)bkImage->originalImage->getHeight(); + + if( dXRatio < dYRatio ) + { + dwNewHeight = ::MulDiv(bkImage->originalImage->getHeight(), dwNewWidth, bkImage->originalImage->getWidth()); + } + else + { + dwNewWidth = ::MulDiv(bkImage->originalImage->getWidth(), dwNewHeight, bkImage->originalImage->getHeight()); + } + } + break; + + case imagePositionFill: + { + double dXRatio = (double)dwNewWidth / (double)bkImage->originalImage->getWidth (); + double dYRatio = (double)dwNewHeight / (double)bkImage->originalImage->getHeight(); + + if( dXRatio > dYRatio ) + { + dwNewHeight = ::MulDiv(bkImage->originalImage->getHeight(), dwNewWidth, bkImage->originalImage->getWidth()); + } + else + { + dwNewWidth = ::MulDiv(bkImage->originalImage->getWidth(), dwNewHeight, bkImage->originalImage->getHeight()); + } + } + break; + } +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr ImageHandler::GetImage(const ImageData& imageData) { - shared_ptr bkImage(new BackgroundImage(imageData)); + std::shared_ptr bkImage(new BackgroundImage(imageData)); Images::iterator itImage = m_images.begin(); @@ -34,7 +113,7 @@ shared_ptr ImageHandler::GetImage(const ImageData& imageData) if (itImage != m_images.end()) return *itImage; // else, try to load image - if (!LoadImage(bkImage)) return shared_ptr(); + if (!LoadImage(bkImage)) return std::shared_ptr(); m_images.push_back(bkImage); @@ -46,9 +125,9 @@ shared_ptr ImageHandler::GetImage(const ImageData& imageData) ////////////////////////////////////////////////////////////////////////////// -shared_ptr ImageHandler::GetDesktopImage(ImageData& imageData) +std::shared_ptr ImageHandler::GetDesktopImage(ImageData& imageData) { - if (!GetDesktopImageData(imageData)) return shared_ptr(); + if (!GetDesktopImageData(imageData)) return std::shared_ptr(); // now, find the image Images::iterator itImage = m_images.begin(); @@ -59,11 +138,11 @@ shared_ptr ImageHandler::GetDesktopImage(ImageData& imageData) if (itImage != m_images.end()) return *itImage; // else, try to load image - shared_ptr bkImage(new BackgroundImage(imageData)); + std::shared_ptr bkImage(new BackgroundImage(imageData)); bkImage->bWallpaper = true; -// if (!LoadImage(bkImage)) return shared_ptr(); +// if (!LoadImage(bkImage)) return std::shared_ptr(); // we always return background image, even if there's no wallpaper selected LoadImage(bkImage); @@ -96,7 +175,7 @@ void ImageHandler::ReloadDesktopImages() ////////////////////////////////////////////////////////////////////////////// -void ImageHandler::UpdateImageBitmap(const CDC& dc, const CRect& clientRect, shared_ptr& bkImage) +void ImageHandler::UpdateImageBitmap(const CDC& dc, const CRect& clientRect, std::shared_ptr& bkImage) { if (bkImage->imageData.bRelative) { @@ -139,7 +218,7 @@ bool ImageHandler::GetDesktopImageData(ImageData& imageData) if (keyColors.QueryStringValue(L"Background", strBackground.GetBuffer(dwDataSize), &dwDataSize) != ERROR_SUCCESS) { strBackground.ReleaseBuffer(); - return shared_ptr(); + return std::shared_ptr(); } strBackground.ReleaseBuffer(); @@ -179,17 +258,30 @@ bool ImageHandler::GetDesktopImageData(ImageData& imageData) if (strWallpaperTile == L"1") { - imageData.imagePosition= imgPosTile; + imageData.imagePosition= imagePositionTile; } else { if (strWallpaperStyle == L"0") { - imageData.imagePosition= imgPosCenter; + imageData.imagePosition= imagePositionCenter; + } + else if (strWallpaperStyle == L"6") + { + imageData.imagePosition= imagePositionFit; + } + else if (strWallpaperStyle == L"10") + { + imageData.imagePosition= imagePositionFill; + } + else if (strWallpaperStyle == L"22") + { + imageData.imagePosition= imagePositionFill; + imageData.bExtend = true; } else { - imageData.imagePosition= imgPosFit; + imageData.imagePosition= imagePositionStretch; } } @@ -201,13 +293,13 @@ bool ImageHandler::GetDesktopImageData(ImageData& imageData) ////////////////////////////////////////////////////////////////////////////// -bool ImageHandler::LoadImage(shared_ptr& bkImage) +bool ImageHandler::LoadImage(std::shared_ptr& bkImage) { USES_CONVERSION; 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()) @@ -231,7 +323,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; } @@ -241,115 +333,142 @@ bool ImageHandler::LoadImage(shared_ptr& bkImage) ////////////////////////////////////////////////////////////////////////////// -void ImageHandler::CreateRelativeImage(const CDC& dc, shared_ptr& bkImage) +void ImageHandler::PaintRelativeImage(const CDC& dc, CBitmap& bmpTemplate, std::shared_ptr& bkImage, DWORD& dwDisplayWidth, DWORD& dwDisplayHeight) { - CriticalSectionLock lock(bkImage->updateCritSec); - - DWORD dwPrimaryDisplayWidth = ::GetSystemMetrics(SM_CXSCREEN); - DWORD dwPrimaryDisplayHeight = ::GetSystemMetrics(SM_CYSCREEN); - - bkImage->dwImageWidth = ::GetSystemMetrics(SM_CXVIRTUALSCREEN); - bkImage->dwImageHeight = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); - - // create background DC - bkImage->dcImage.CreateCompatibleDC(NULL); - - // create background bitmap - Helpers::CreateBitmap(dc, bkImage->dwImageWidth, bkImage->dwImageHeight, bkImage->image); - bkImage->dcImage.SelectBitmap(bkImage->image); - - // paint background - CBrush backgroundBrush(::CreateSolidBrush(bkImage->imageData.crBackground)); - CRect rect(0, 0, bkImage->dwImageWidth, bkImage->dwImageHeight); - bkImage->dcImage.FillRect(&rect, backgroundBrush); - - // this can be false only for desktop backgrounds with no wallpaper image - if (bkImage->originalImage.get() != NULL) - { - // create template image - CDC dcTemplate; - CBitmap bmpTemplate; - - dcTemplate.CreateCompatibleDC(NULL); - - // set template bitmap dimensions - DWORD dwTemplateWidth = bkImage->originalImage->getWidth(); - DWORD dwTemplateHeight = bkImage->originalImage->getHeight(); - - if (bkImage->imageData.imagePosition == imgPosFit) - { - if (bkImage->imageData.bExtend) - { - dwTemplateWidth = bkImage->dwImageWidth; - dwTemplateHeight= bkImage->dwImageHeight; - } - else - { - dwTemplateWidth = dwPrimaryDisplayWidth; - dwTemplateHeight= dwPrimaryDisplayHeight; - } - } - - if ((bkImage->originalImage->getWidth() != dwTemplateWidth) || - (bkImage->originalImage->getHeight() != dwTemplateHeight)) - { - // resize background image - fipImage tempImage(*(bkImage->originalImage)); - tempImage.rescale(static_cast(dwTemplateWidth), static_cast(dwTemplateHeight), FILTER_BILINEAR); - - bmpTemplate.CreateDIBitmap( - 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(), - DIB_RGB_COLORS); - } - - dcTemplate.SelectBitmap(bmpTemplate); - - if (bkImage->imageData.imagePosition == imgPosTile) - { - TileTemplateImage( - dcTemplate, - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - ::GetSystemMetrics(SM_YVIRTUALSCREEN), - bkImage); - - } - else - { - if (bkImage->imageData.bExtend) - { - PaintTemplateImage( - dcTemplate, - 0, - 0, - bkImage->dwImageWidth, - bkImage->dwImageHeight, - bkImage->dwImageWidth, - bkImage->dwImageHeight, - bkImage); - } - else - { - MonitorEnumData enumData(dcTemplate, bkImage); - ::EnumDisplayMonitors(NULL, NULL, ImageHandler::MonitorEnumProc, reinterpret_cast(&enumData)); - } - } - } + // set template bitmap dimensions + DWORD dwTemplateWidth = bkImage->originalImage->getWidth(); + DWORD dwTemplateHeight = bkImage->originalImage->getHeight(); + + if (bkImage->imageData.imagePosition == imagePositionStretch || + bkImage->imageData.imagePosition == imagePositionFit || + bkImage->imageData.imagePosition == imagePositionFill) + { + if (bkImage->imageData.bExtend) + { + dwTemplateWidth = bkImage->dwImageWidth; + dwTemplateHeight = bkImage->dwImageHeight; + } + else + { + dwTemplateWidth = dwDisplayWidth; + dwTemplateHeight = dwDisplayHeight; + } + } + + DWORD dwNewWidth = dwTemplateWidth; + DWORD dwNewHeight = dwTemplateHeight; + + if ( bkImage->originalImage->getWidth() != dwNewWidth || + bkImage->originalImage->getHeight() != dwNewHeight ) + { + // resize background image + ImageHandler::CalcRescale(dwNewWidth, dwNewHeight, bkImage); + fipImage tempImage(*(bkImage->originalImage)); + +#ifdef _DEBUG + DWORD dwGetTickCount = ::GetTickCount(); +#endif + tempImage.rescale(dwNewWidth, dwNewHeight, FILTER_BILINEAR); +#ifdef _DEBUG + TRACE(L"rescale in %lu ms\n", ::GetTickCount() - dwGetTickCount); +#endif + + bmpTemplate.CreateDIBitmap( + 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(), + DIB_RGB_COLORS); + } + + dwDisplayWidth = dwNewWidth; + dwDisplayHeight = dwNewHeight; +} - if (bkImage->imageData.byTintOpacity > 0) TintImage(dc, bkImage); +void ImageHandler::CreateRelativeImage(const CDC& dc, std::shared_ptr& bkImage) +{ + CriticalSectionLock lock(bkImage->updateCritSec); + + bkImage->dwImageWidth = ::GetSystemMetrics(SM_CXVIRTUALSCREEN); + bkImage->dwImageHeight = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); + + // create background DC + bkImage->dcImage.CreateCompatibleDC(NULL); + + // create background bitmap + Helpers::CreateBitmap(dc, bkImage->dwImageWidth, bkImage->dwImageHeight, bkImage->image); + bkImage->dcImage.SelectBitmap(bkImage->image); + + // paint background + CBrush backgroundBrush(::CreateSolidBrush(bkImage->imageData.crBackground)); + CRect rect(0, 0, bkImage->dwImageWidth, bkImage->dwImageHeight); + bkImage->dcImage.FillRect(&rect, backgroundBrush); + + // this can be false only for desktop backgrounds with no wallpaper image + if (bkImage->originalImage.get() != NULL) + { + if (bkImage->imageData.imagePosition == imagePositionTile || + bkImage->imageData.bExtend || + !ImageHandler::IsWin8()) + { + // create template image + CDC dcTemplate; + CBitmap bmpTemplate; + dcTemplate.CreateCompatibleDC(NULL); + + // Windows 7 or older wallpaper (Stretch, Fit & Fill) use the primary monitor to rescale picture for each monitor + DWORD dwNewWidth = ::GetSystemMetrics(SM_CXSCREEN); + DWORD dwNewHeight = ::GetSystemMetrics(SM_CYSCREEN); + PaintRelativeImage(dc, bmpTemplate, bkImage, dwNewWidth, dwNewHeight); + + dcTemplate.SelectBitmap(bmpTemplate); + + if (bkImage->imageData.imagePosition == imagePositionTile) + { + ImageHandler::TileTemplateImage( + dcTemplate, + ImageHandler::IsWin8() ? 0 : ::GetSystemMetrics(SM_XVIRTUALSCREEN), // Windows 8 wallpaper tiles starts + ImageHandler::IsWin8() ? 0 : ::GetSystemMetrics(SM_YVIRTUALSCREEN), // in the top left corner of virtual screen + bkImage); + } + else if (bkImage->imageData.bExtend) + { + ImageHandler::PaintTemplateImage( + dcTemplate, + 0, + 0, + dwNewWidth, + dwNewHeight, + bkImage->dwImageWidth, + bkImage->dwImageHeight, + bkImage); + } + else + { + MonitorEnumData enumData(dcTemplate, bkImage); + ::EnumDisplayMonitors(NULL, NULL, ImageHandler::MonitorEnumProc, reinterpret_cast(&enumData)); + } + } + else + { + // Windows 8 wallpaper (Stretch, Fit & Fill) is handled separately for each monitor + MonitorEnumData enumData(dc, bkImage); + ::EnumDisplayMonitors(NULL, NULL, ImageHandler::MonitorEnumProcWin8, reinterpret_cast(&enumData)); + } + } + + if (bkImage->imageData.byTintOpacity > 0) TintImage(dc, bkImage); } ////////////////////////////////////////////////////////////////////////////// @@ -357,7 +476,7 @@ void ImageHandler::CreateRelativeImage(const CDC& dc, shared_ptr& bkImage) +void ImageHandler::CreateImage(const CDC& dc, const CRect& clientRect, std::shared_ptr& bkImage) { CriticalSectionLock lock(bkImage->updateCritSec); @@ -385,53 +504,61 @@ 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))) + DWORD dwNewWidth = bkImage->dwImageWidth; + DWORD dwNewHeight = bkImage->dwImageHeight; + + if ( (bkImage->imageData.imagePosition == imagePositionStretch || + bkImage->imageData.imagePosition == imagePositionFit || + bkImage->imageData.imagePosition == imagePositionFill) + && + (bkImage->originalImage->getWidth() != dwNewWidth || + bkImage->originalImage->getHeight() != dwNewHeight) ) { // resize background image + ImageHandler::CalcRescale(dwNewWidth, dwNewHeight, bkImage); fipImage tempImage(*(bkImage->originalImage)); - tempImage.rescale(static_cast(bkImage->dwImageWidth), static_cast(bkImage->dwImageHeight), FILTER_BILINEAR); + tempImage.rescale(dwNewWidth, dwNewHeight, 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); } dcTemplate.SelectBitmap(bmpTemplate); - if (bkImage->imageData.imagePosition == imgPosTile) + if (bkImage->imageData.imagePosition == imagePositionTile) { TileTemplateImage( - dcTemplate, - 0, - 0, + dcTemplate, + 0, + 0, bkImage); } else { PaintTemplateImage( - dcTemplate, - 0, + dcTemplate, + 0, 0, - bkImage->dwImageWidth, - bkImage->dwImageHeight, - bkImage->dwImageWidth, - bkImage->dwImageHeight, + dwNewWidth, + dwNewHeight, + bkImage->dwImageWidth, + bkImage->dwImageHeight, bkImage); } } @@ -444,9 +571,9 @@ 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) +void ImageHandler::PaintTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, DWORD dwSrcWidth, DWORD dwSrcHeight, DWORD dwDstWidth, DWORD dwDstHeight, std::shared_ptr& bkImage) { - if (bkImage->imageData.imagePosition == imgPosCenter) + if (bkImage->imageData.imagePosition == imagePositionCenter) { bkImage->dcImage.BitBlt( (dwDstWidth <= bkImage->dwOriginalImageWidth) ? nOffsetX : nOffsetX + (dwDstWidth - bkImage->dwOriginalImageWidth)/2, @@ -458,7 +585,22 @@ void ImageHandler::PaintTemplateImage(const CDC& dcTemplate, int nOffsetX, int n (dwDstHeight < bkImage->dwOriginalImageHeight) ? (bkImage->dwOriginalImageHeight - dwDstHeight)/2 : 0, SRCCOPY); } - else + else if (bkImage->imageData.imagePosition == imagePositionFill && ImageHandler::IsWin8()) + { + // Windows 8 filled wallpaper: + // when image height is greater than screen height + // top is not shifted with half but 1/3 + bkImage->dcImage.BitBlt( + (dwDstWidth <= dwSrcWidth) ? nOffsetX : nOffsetX + (dwDstWidth - dwSrcWidth)/2, + (dwDstHeight <= dwSrcHeight) ? nOffsetY : nOffsetY + (dwDstHeight - dwSrcHeight)/3, + dwDstWidth, + dwDstHeight, + dcTemplate, + (dwDstWidth < dwSrcWidth) ? (dwSrcWidth - dwDstWidth)/2 : 0, + (dwDstHeight < dwSrcHeight) ? (dwSrcHeight - dwDstHeight)/3 : 0, + SRCCOPY); + } + else { bkImage->dcImage.BitBlt( (dwDstWidth <= dwSrcWidth) ? nOffsetX : nOffsetX + (dwDstWidth - dwSrcWidth)/2, @@ -477,7 +619,7 @@ void ImageHandler::PaintTemplateImage(const CDC& dcTemplate, int nOffsetX, int n ////////////////////////////////////////////////////////////////////////////// -void ImageHandler::TileTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, shared_ptr& bkImage) +void ImageHandler::TileTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, std::shared_ptr& bkImage) { // we're tiling the image, starting at coordinates (0, 0) DWORD dwX = 0; @@ -517,7 +659,7 @@ void ImageHandler::TileTemplateImage(const CDC& dcTemplate, int nOffsetX, int nO ////////////////////////////////////////////////////////////////////////////// -void ImageHandler::TintImage(const CDC& dc, shared_ptr& bkImage) +void ImageHandler::TintImage(const CDC& dc, std::shared_ptr& bkImage) { CDC dcTint; CBitmap bmpTint; @@ -563,17 +705,19 @@ BOOL CALLBACK ImageHandler::MonitorEnumProc(HMONITOR /*hMonitor*/, HDC /*hdcMoni { MonitorEnumData* pEnumData = reinterpret_cast(lpData); - CRect rectMonitor(lprcMonitor); - DWORD dwPrimaryDisplayWidth = ::GetSystemMetrics(SM_CXSCREEN); - DWORD dwPrimaryDisplayHeight = ::GetSystemMetrics(SM_CYSCREEN); + CRect rectMonitor(lprcMonitor); + + DWORD dwNewWidth = ::GetSystemMetrics(SM_CXSCREEN); + DWORD dwNewHeight = ::GetSystemMetrics(SM_CYSCREEN); + ImageHandler::CalcRescale(dwNewWidth, dwNewHeight, pEnumData->bkImage); ImageHandler::PaintTemplateImage( pEnumData->dcTemplate, rectMonitor.left - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - rectMonitor.top - ::GetSystemMetrics(SM_YVIRTUALSCREEN), - dwPrimaryDisplayWidth, - dwPrimaryDisplayHeight, + rectMonitor.top - ::GetSystemMetrics(SM_YVIRTUALSCREEN), + dwNewWidth, + dwNewHeight, rectMonitor.Width(), rectMonitor.Height(), pEnumData->bkImage); @@ -582,3 +726,163 @@ BOOL CALLBACK ImageHandler::MonitorEnumProc(HMONITOR /*hMonitor*/, HDC /*hdcMoni } ////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK ImageHandler::MonitorEnumProcWin8(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM lpData) +{ + MONITORINFOEX miex; + miex.cbSize = sizeof(miex); + ::GetMonitorInfo(hMonitor, &miex); + + DISPLAY_DEVICE dd; + dd.cb = sizeof(dd); + ::EnumDisplayDevices(miex.szDevice, 0, &dd, EDD_GET_DEVICE_INTERFACE_NAME); + +#if 0 + TRACE(L"name %s String %s DeviceID %s Key %s StateFlags %lu\n", + dd.DeviceName, + dd.DeviceString, + dd.DeviceID, + dd.DeviceKey, + dd.StateFlags); +#endif + + wchar_t szTranscodedImage [_MAX_PATH] = L""; + + TRACE( + L"searching for %s ('%s') ...\n", + miex.szDevice, + dd.DeviceID); + + try + { + DWORD dwTranscodedImageCount = 0; + DWORD dwType; + DWORD dwValueSize; + LSTATUS rc; + + HKEY hkey; + rc = ::RegOpenKeyEx( + HKEY_CURRENT_USER, + L"Control Panel\\Desktop", + 0, + KEY_READ, + &hkey); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + unique_ptrhkeyPtr(hkey); + + rc = ::RegQueryValueEx( + hkeyPtr.get(), + L"TranscodedImageCount", + nullptr, + &dwType, + reinterpret_cast(&dwTranscodedImageCount), + &(dwValueSize = static_cast(sizeof(dwTranscodedImageCount)))); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + for(DWORD i = 0; i < dwTranscodedImageCount; ++i) + { + wchar_t szValueName [32]; + _snwprintf_s( + szValueName, ARRAYSIZE(szValueName), + _TRUNCATE, + L"TranscodedImageCache_%03lu", + i); + + BYTE binTranscodedImageCache [0x320]; + rc = ::RegQueryValueEx( + hkeyPtr.get(), + szValueName, + nullptr, + &dwType, + binTranscodedImageCache, + &(dwValueSize = static_cast(sizeof(binTranscodedImageCache)))); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + TRACE( + L"\twallpaper picture on ('%s') is '%s'\n", + reinterpret_cast(binTranscodedImageCache + 0x220), + reinterpret_cast(binTranscodedImageCache + 0x18)); + + wchar_t* szDeviceID1 = dd.DeviceID; + wchar_t* szDeviceID2 = reinterpret_cast(binTranscodedImageCache + 0x220); + + // when monitor device id is "Default_Monitor" + // \\?\DISPLAY#Default_Monitor#... + // there is no device id in TranscodedImageCache_xxx file + + if( ( *szDeviceID2 == 0 && + wcsncmp(szDeviceID1, L"\\\\?\\DISPLAY#Default_Monitor#", 28) == 0 ) || + wcsncmp(szDeviceID1, szDeviceID2, 128) == 0 ) + { + wcsncpy_s( + szTranscodedImage, _MAX_PATH, + reinterpret_cast(binTranscodedImageCache + 0x18), + _TRUNCATE); + + break; + } + } + } + catch(Win32Exception&) + { + } + + MonitorEnumData* pEnumData = reinterpret_cast(lpData); + + std::shared_ptr bkImage; + + if( szTranscodedImage[0] ) + { + TRACE( + L"wallpaper picture on %s ('%s') is '%s'\n", + miex.szDevice, + dd.DeviceID, + szTranscodedImage); + + bkImage.reset(new BackgroundImage (pEnumData->bkImage->imageData)); + bkImage->imageData.strFilename = szTranscodedImage; + bkImage->bWallpaper = true; + ImageHandler::LoadImageW(bkImage); + } + else + { + bkImage = pEnumData->bkImage; + } + + CRect rectMonitor(lprcMonitor); + + // create template image + CDC dcTemplate; + CBitmap bmpTemplate; + dcTemplate.CreateCompatibleDC(NULL); + + DWORD dwNewWidth = rectMonitor.Width(); + DWORD dwNewHeight = rectMonitor.Height(); + ImageHandler::PaintRelativeImage(pEnumData->dcTemplate, bmpTemplate, bkImage, dwNewWidth, dwNewHeight); + + dcTemplate.SelectBitmap(bmpTemplate); + + ImageHandler::PaintTemplateImage( + dcTemplate, + rectMonitor.left - ::GetSystemMetrics(SM_XVIRTUALSCREEN), + rectMonitor.top - ::GetSystemMetrics(SM_YVIRTUALSCREEN), + dwNewWidth, + dwNewHeight, + rectMonitor.Width(), + rectMonitor.Height(), + pEnumData->bkImage); + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/ImageHandler.h b/Console/ImageHandler.h index 42e0d9dd..6d42ae8e 100644 --- a/Console/ImageHandler.h +++ b/Console/ImageHandler.h @@ -6,9 +6,20 @@ enum ImagePosition { - imgPosCenter = 0, - imgPosFit = 1, - imgPosTile = 2 + /* new names like Win7 walppaper settings */ + imagePositionCenter = 0, + imagePositionStretch = 1, + imagePositionTile = 2, + imagePositionFit = 3, + imagePositionFill = 4, + + /* old names */ + /* + imgPosCenter = 0, + imgPosFit = 1, + imgPosTile = 2, + imgPosFitWithAspectRatio = 3 + */ }; ////////////////////////////////////////////////////////////////////////////// @@ -22,7 +33,7 @@ struct ImageData : strFilename(L"") , bRelative(false) , bExtend(false) - , imagePosition(imgPosCenter) + , imagePosition(imagePositionCenter) , crBackground(RGB(0, 0, 0)) , crTint(RGB(0, 0, 0)) , byTintOpacity(0) @@ -120,7 +131,7 @@ struct BackgroundImage bool bWallpaper; - shared_ptr originalImage; + std::shared_ptr originalImage; CBitmap image; CDC dcImage; @@ -130,19 +141,19 @@ struct BackgroundImage struct MonitorEnumData { - MonitorEnumData(CDC& dcTempl, shared_ptr& img) + MonitorEnumData(const CDC& dcTempl, std::shared_ptr& img) : bkImage(img) , dcTemplate(dcTempl) { } - shared_ptr& bkImage; - CDC& dcTemplate; + std::shared_ptr& bkImage; + const CDC& dcTemplate; }; ////////////////////////////////////////////////////////////////////////////// -typedef vector > Images; +typedef vector > Images; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -160,32 +171,37 @@ class ImageHandler public: - shared_ptr GetImage(const ImageData& imageData); - shared_ptr GetDesktopImage(ImageData& imageData); + std::shared_ptr GetImage(const ImageData& imageData); + std::shared_ptr GetDesktopImage(ImageData& imageData); void ReloadDesktopImages(); - void UpdateImageBitmap(const CDC& dc, const CRect& clientRect, shared_ptr& bkImage); + void UpdateImageBitmap(const CDC& dc, const CRect& clientRect, std::shared_ptr& bkImage); + static inline bool IsWin8(void) { return m_win8; } private: - bool GetDesktopImageData(ImageData& imageData); - bool LoadImage(shared_ptr& bkImage); + static bool GetDesktopImageData(ImageData& imageData); + static bool LoadImage(std::shared_ptr& bkImage); - void CreateRelativeImage(const CDC& dc, shared_ptr& bkImage); - void CreateImage(const CDC& dc, const CRect& clientRect, shared_ptr& bkImage); + static void CalcRescale(DWORD& dwNewWidth, DWORD& dwNewHeight, std::shared_ptr& bkImage); + static void PaintRelativeImage(const CDC& dc, CBitmap& bmpTemplate, std::shared_ptr& bkImage, DWORD& dwDisplayWidth, DWORD& dwDisplayHeight); + static void CreateRelativeImage(const CDC& dc, std::shared_ptr& bkImage); + static void CreateImage(const CDC& dc, const CRect& clientRect, std::shared_ptr& bkImage); - static void PaintTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, DWORD dwSrcWidth, DWORD dwSrcHeight, DWORD dwDstWidth, DWORD dwDstHeight, shared_ptr& bkImage); - static void TileTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, shared_ptr& bkImage); + static void PaintTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, DWORD dwSrcWidth, DWORD dwSrcHeight, DWORD dwDstWidth, DWORD dwDstHeight, std::shared_ptr& bkImage); + static void TileTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, std::shared_ptr& bkImage); - void TintImage(const CDC& dc, shared_ptr& bkImage); + static void TintImage(const CDC& dc, std::shared_ptr& bkImage); // called by the ::EnumDisplayMonitors to create background for each display static BOOL CALLBACK MonitorEnumProc(HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM lpData); - + static BOOL CALLBACK MonitorEnumProcWin8(HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM lpData); + static bool CheckWin8(void); private: Images m_images; + static bool m_win8; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/JumpList.cpp b/Console/JumpList.cpp new file mode 100644 index 00000000..0408b26e --- /dev/null +++ b/Console/JumpList.cpp @@ -0,0 +1,155 @@ +// code found in http://win7shell.googlecode.com/svn/trunk/jumplist.cpp + +#include "StdAfx.h" +#include "JumpList.h" +#include "Console.h" + +#include +#include +#include + +// Creates a CLSID_ShellLink to insert into the Tasks section of the Jump List. This type of Jump +// List item allows the specification of an explicit command line to execute the task. +static HRESULT _CreateShellLink(PCWSTR pszArguments, PCWSTR pszTitle, IShellLink **ppsl) +{ + CComPtr psl; + HRESULT hr = psl.CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER); + if (FAILED(hr)) + return hr; + + // path + wchar_t szModulePath[MAX_PATH]; + ::ZeroMemory(szModulePath, sizeof(szModulePath)); + if( !::GetModuleFileName(NULL, szModulePath, MAX_PATH) ) + return HRESULT_FROM_WIN32(::GetLastError()); + + hr = psl->SetPath(szModulePath); + if (FAILED(hr)) + return hr; + + // arguments + hr = psl->SetArguments(pszArguments); + if (FAILED(hr)) + return hr; + + // The title property is required on Jump List items provided as an IShellLink + // instance. This value is used as the display name in the Jump List. + CComPtr pps; + hr = psl.QueryInterface(&pps); + if (FAILED(hr)) + return hr; + + PROPVARIANT propvar; + hr = ::InitPropVariantFromString(pszTitle, &propvar); + if (FAILED(hr)) + return hr; + + hr = pps->SetValue(PKEY_Title, propvar); + ::PropVariantClear(&propvar); + if (FAILED(hr)) + return hr; + + hr = pps->Commit(); + if (FAILED(hr)) + return hr; + + hr = psl->SetWorkingDirectory(g_settingsHandler->GetSettingsPath().c_str()); + if (FAILED(hr)) + return hr; + + *ppsl = psl.Detach(); + + return hr; +} + +static HRESULT SetIconLocation(IShellLink *psl, LPCWSTR szIconLocation) +{ + wchar_t szIconLocationFullName[_MAX_PATH]; + if( !::GetFullPathName(szIconLocation, ARRAYSIZE(szIconLocationFullName), szIconLocationFullName, 0) ) + return HRESULT_FROM_WIN32(::GetLastError()); + + return psl->SetIconLocation(szIconLocationFullName, 0); +} + +static HRESULT SetIcon(IShellLink *psl, std::shared_ptr tab) +{ + if (tab->bUseDefaultIcon) + { + if ( !tab->strShell.empty() ) + { + wstring strCommandLine = Helpers::ExpandEnvironmentStrings(tab->strShell); + int argc = 0; + std::unique_ptr argv(::CommandLineToArgvW(strCommandLine.c_str(), &argc)); + + if ( argv && argc > 0 ) + { + return ::SetIconLocation(psl, argv[0]); + } + } + } + else + { + if (!tab->strIcon.empty()) + { + return ::SetIconLocation(psl, Helpers::ExpandEnvironmentStrings(tab->strIcon).c_str()); + } + } + + wchar_t szModulePath[MAX_PATH]; + ::ZeroMemory(szModulePath, sizeof(szModulePath)); + ::GetModuleFileName(NULL, szModulePath, MAX_PATH); + + return ::SetIconLocation(psl, szModulePath); +} + +void JumpList::CreateList(TabDataVector& tabDataVector) +{ + if( !g_settingsHandler->GetAppearanceSettings().stylesSettings.bJumplist ) + return; + + CComPtr pcdl; + HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER); + if (FAILED(hr)) + return; + + UINT cMinSlots; + CComPtr poaRemoved; + hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved)); + if (FAILED(hr)) + return; + + CComPtr poc; + hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC); + if (FAILED(hr)) + return; + + for (TabDataVector::iterator it = tabDataVector.begin(); it != tabDataVector.end(); ++it) + { + CComPtr psl; + wstring quotedName(L"-reuse -t \""); + quotedName.append((*it)->strTitle); + quotedName.append(L"\" -c \""); + quotedName.append(g_settingsHandler->GetSettingsFileName()); + quotedName.append(L"\""); + if (SUCCEEDED(_CreateShellLink(quotedName.c_str(), (*it)->strTitle.c_str(), &psl))) + { + SetIcon(psl, *it); + poc->AddObject(psl); + } + } + + CComPtr poa; + hr = poc->QueryInterface(IID_PPV_ARGS(&poa)); + if (FAILED(hr)) + return; + + // Add the tasks to the Jump List. Tasks always appear in the canonical "Tasks" + // category that is displayed at the bottom of the Jump List, after all other + // categories. + //hr = pcdl->AddUserTasks(poa); + hr = pcdl->AppendCategory(g_settingsHandler->GetSettingsTitle().c_str(),poa); + if (FAILED(hr)) + return; + + hr = pcdl->CommitList(); +} diff --git a/Console/JumpList.h b/Console/JumpList.h new file mode 100644 index 00000000..5f773df1 --- /dev/null +++ b/Console/JumpList.h @@ -0,0 +1,7 @@ +#pragma once +class JumpList +{ +public: + static void CreateList(TabDataVector &tabDataVector); +}; + diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 3b5db90e..052cce00 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -3,10 +3,13 @@ #include "aboutdlg.h" #include "Console.h" +#include "TabView.h" #include "ConsoleView.h" +#include "ConsoleException.h" #include "DlgRenameTab.h" #include "DlgSettingsMain.h" #include "MainFrame.h" +#include "JumpList.h" ////////////////////////////////////////////////////////////////////////////// @@ -17,23 +20,75 @@ ////////////////////////////////////////////////////////////////////////////// +static void ParseCommandLine +( + LPCTSTR lptstrCmdLine, + wstring& strWindowTitle, + vector& startupTabs, + vector& startupDirs, + vector& startupCmds, + int& nMultiStartSleep +) +{ + int argc = 0; + std::unique_ptr argv(::CommandLineToArgvW(lptstrCmdLine, &argc)); + + if (argc < 1) return; + + for (int i = 0; i < argc; ++i) + { + if (wstring(argv[i]) == wstring(L"-w")) + { + // startup tab name + ++i; + if (i == argc) break; + strWindowTitle = argv[i]; + } + else if (wstring(argv[i]) == wstring(L"-t")) + { + // startup tab name + ++i; + if (i == argc) break; + startupTabs.push_back(argv[i]); + } + else if (wstring(argv[i]) == wstring(L"-d")) + { + // startup dir + ++i; + if (i == argc) break; + startupDirs.push_back(argv[i]); + } + else if (wstring(argv[i]) == wstring(L"-r")) + { + // startup cmd + ++i; + if (i == argc) break; + startupCmds.push_back(argv[i]); + } + else if (wstring(argv[i]) == wstring(L"-ts")) + { + // startup tab sleep for multiple tabs + ++i; + if (i == argc) break; + nMultiStartSleep = _wtoi(argv[i]); + if (nMultiStartSleep < 0) nMultiStartSleep = 500; + } + } + + // make sure that startupDirs and startupCmds are at least as big as startupTabs + if (startupDirs.size() < startupTabs.size()) startupDirs.resize(startupTabs.size()); + if (startupCmds.size() < startupTabs.size()) startupCmds.resize(startupTabs.size()); +} MainFrame::MainFrame ( - const wstring strWindowTitle, - const vector& startupTabs, - const vector& startupDirs, - const vector& startupCmds, - int nMultiStartSleep, - const wstring& strDbgCmdLine + LPCTSTR lpstrCmdLine ) : m_bOnCreateDone(false) -, m_startupTabs(startupTabs) -, m_startupDirs(startupDirs) -, m_startupCmds(startupCmds) -, m_nMultiStartSleep(nMultiStartSleep) -, m_strDbgCmdLine(strDbgCmdLine) -, m_activeView() +, m_startupTabs(vector(0)) +, m_startupDirs(vector(0)) +, m_startupCmds(vector(0)) +, m_activeTabView() , m_bMenuVisible(TRUE) , m_bToolbarVisible(TRUE) , m_bStatusBarVisible(TRUE) @@ -41,20 +96,31 @@ MainFrame::MainFrame , m_dockPosition(dockNone) , m_zOrder(zorderNormal) , m_mousedragOffset(0, 0) -, m_views() -, m_viewsMutex(NULL, FALSE, NULL) -, m_strCmdLineWindowTitle(strWindowTitle.c_str()) -, m_strWindowTitle(strWindowTitle.c_str()) -, m_dwRows(0) -, m_dwColumns(0) +, m_tabs() +, m_tabsMutex(NULL, FALSE, NULL) , m_dwWindowWidth(0) , m_dwWindowHeight(0) , m_dwResizeWindowEdge(WMSZ_BOTTOM) , m_bRestoringWindow(false) , m_rectRestoredWnd(0, 0, 0, 0) -, m_animationWindow() +, m_bAppActive(true) { + m_Margins.cxLeftWidth = 0; + m_Margins.cxRightWidth = 0; + m_Margins.cyTopHeight = 0; + m_Margins.cyBottomHeight = 0; + + wstring strWindowTitle(L""); + ParseCommandLine( + lpstrCmdLine, + strWindowTitle, + m_startupTabs, + m_startupDirs, + m_startupCmds, + m_nMultiStartSleep); + m_strCmdLineWindowTitle = strWindowTitle.c_str(); + m_strWindowTitle = strWindowTitle.c_str(); } ////////////////////////////////////////////////////////////////////////////// @@ -73,9 +139,9 @@ BOOL MainFrame::PreTranslateMessage(MSG* pMsg) if(CTabbedFrameImpl::PreTranslateMessage(pMsg)) return TRUE; - if (m_activeView.get() == NULL) return FALSE; + if (!m_activeTabView) return FALSE; - return m_activeView->PreTranslateMessage(pMsg); + return m_activeTabView->PreTranslateMessage(pMsg); } ////////////////////////////////////////////////////////////////////////////// @@ -85,18 +151,73 @@ BOOL MainFrame::PreTranslateMessage(MSG* pMsg) BOOL MainFrame::OnIdle() { - UpdateStatusBar(); - UIUpdateToolBar(); - return FALSE; + UpdateStatusBar(); + UIUpdateToolBar(); + + return FALSE; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// +LRESULT MainFrame::CreateInitialTabs +( + vector startupTabs, + vector startupCmds, + vector startupDirs, + int nMultiStartSleep +) +{ + bool bAtLeastOneStarted = false; + + // create initial console window(s) + if (startupTabs.size() == 0) + { + wstring strStartupDir(L""); + wstring strStartupCmd(L""); + + if (startupDirs.size() > 0) strStartupDir = startupDirs[0]; + if (startupCmds.size() > 0) strStartupCmd = startupCmds[0]; + + bAtLeastOneStarted = CreateNewConsole(0, strStartupDir, strStartupCmd); + } + else + { + TabSettings& tabSettings = g_settingsHandler->GetTabSettings(); + + for (size_t tabIndex = 0; tabIndex < startupTabs.size(); ++tabIndex) + { + // find tab with corresponding name... + for (size_t i = 0; i < tabSettings.tabDataVector.size(); ++i) + { + wstring str = tabSettings.tabDataVector[i]->strTitle; + if (tabSettings.tabDataVector[i]->strTitle == startupTabs[tabIndex]) + { + // -ts Specifies sleep time between starting next tab if multiple -t's are specified. + if (bAtLeastOneStarted) ::Sleep(nMultiStartSleep); + // found it, create + if (CreateNewConsole( + static_cast(i), + startupDirs[tabIndex], + startupCmds[tabIndex])) + { + bAtLeastOneStarted = true; + } + break; + } + } + } + } + + return bAtLeastOneStarted ? 0 : -1; +} 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 @@ -106,7 +227,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,84 +241,64 @@ 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); - - // create initial console window(s) - if (m_startupTabs.size() == 0) - { - wstring strStartupDir(L""); - wstring strStartupCmd(L""); - - 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; - } - else - { - bool bAtLeastOneStarted = false; - TabSettings& tabSettings = g_settingsHandler->GetTabSettings(); + DWORD dwTabStyles = CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK; + if (controlsSettings.bTabsOnBottom) dwTabStyles |= CTCS_BOTTOM; - for (size_t tabIndex = 0; tabIndex < m_startupTabs.size(); ++tabIndex) - { - // find tab with corresponding name... - for (size_t i = 0; i < tabSettings.tabDataVector.size(); ++i) - { - wstring str = tabSettings.tabDataVector[i]->strTitle; - if (tabSettings.tabDataVector[i]->strTitle == m_startupTabs[tabIndex]) - { - // found it, create - if (CreateNewConsole( - static_cast(i), - m_startupDirs[tabIndex], - m_startupCmds[tabIndex], - (i == 0) ? m_strDbgCmdLine : wstring(L""))) - { - bAtLeastOneStarted = true; - } - if (m_startupTabs.size() > 1) ::Sleep(m_nMultiStartSleep); - break; - } - } - } + CreateTabWindow(m_hWnd, rcDefault, dwTabStyles); - // could not start none of the startup tabs, exit - if (!bAtLeastOneStarted) return -1; - } + if (LRESULT created = CreateInitialTabs(m_startupTabs, m_startupCmds, m_startupDirs, m_nMultiStartSleep)) + return created; UIAddToolBar(hWndToolBar); UISetCheck(ID_VIEW_MENU, 1); UISetCheck(ID_VIEW_TOOLBAR, 1); UISetCheck(ID_VIEW_TABS, 1); UISetCheck(ID_VIEW_STATUS_BAR, 1); + UISetBlockAccelerators(true); 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); ShowTabs(controlsSettings.bShowTabs ? TRUE : FALSE); { - MutexLock lock(m_viewsMutex); - if ((m_views.size() == 1) && m_bTabsVisible && (controlsSettings.bHideSingleTab)) + MutexLock lock(m_tabsMutex); + if (m_tabs.size() == 1) + { + UIEnable(ID_FILE_CLOSE_TAB, FALSE); + } + if ((m_tabs.size() == 1) && m_bTabsVisible && (controlsSettings.bHideSingleTab)) { ShowTabs(FALSE); } @@ -237,7 +342,7 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, CreateAcceleratorTable(); RegisterGlobalHotkeys(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); CRect rectWindow; GetWindowRect(&rectWindow); @@ -275,8 +380,24 @@ 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*/) { + + { + MutexLock lock(m_tabsMutex); + + if( m_tabs.size() > 1 ) + { + if( ::MessageBox(m_hWnd, L"Are you sure you want close all tabs ?", L"Close", MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL ) + return 0; + } + else if( m_tabs.size() == 1 && m_tabs.begin()->second->GetViewsCount() > 1 ) + { + if( ::MessageBox(m_hWnd, L"Are you sure you want close all views ?", L"Close", MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL ) + return 0; + } + } + // save settings on exit bool bSaveSettings = false; ConsoleSettings& consoleSettings = g_settingsHandler->GetConsoleSettings(); @@ -284,9 +405,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; } @@ -305,11 +427,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.get() == it->second.get()) m_activeView.reset(); + if (m_activeTabView == it->second) m_activeTabView.reset(); it->second->DestroyWindow(); } @@ -317,7 +439,8 @@ LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, UnregisterGlobalHotkeys(); - bHandled = false; + DestroyWindow(); + PostQuitMessage(0); return 0; } @@ -328,125 +451,171 @@ 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); - - if (m_activeView.get() == NULL) return 0; + m_bAppActive = static_cast(wParam)? true : false; - m_activeView->SetAppActiveStatus(bActivating ? true : false); + if (!m_activeTabView) return 0; - TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; - - if ((transparencySettings.transType == transAlpha) && - ((transparencySettings.byActiveAlpha != 255) || (transparencySettings.byInactiveAlpha != 255))) - { - if (bActivating) - { - ::SetLayeredWindowAttributes(m_hWnd, RGB(0, 0, 0), transparencySettings.byActiveAlpha, LWA_ALPHA); - } - else - { - ::SetLayeredWindowAttributes(m_hWnd, RGB(0, 0, 0), transparencySettings.byInactiveAlpha, LWA_ALPHA); - } - - } - - // we're being called while OnCreate is running, return here - if (!m_bOnCreateDone) - { - bHandled = FALSE; - 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)); + this->ActivateApp(); - m_animationWindow->Create(); - m_animationWindow->SA(); - } -*/ + // we're being called while OnCreate is running, return here + if (!m_bOnCreateDone) + { + bHandled = FALSE; + return 0; + } -// if (bActivating) ::RedrawWindow(m_hWnd, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN); -// } + bHandled = FALSE; - bHandled = FALSE; - return 0; + return 0; } -////////////////////////////////////////////////////////////////////////////// - +void MainFrame::ActivateApp(HWND hwndTabView, HWND hwndConsoleView) +{ + m_bAppActive = TRUE; -////////////////////////////////////////////////////////////////////////////// + // find the tab + MutexLock viewMapLock(m_tabsMutex); + auto it = m_tabs.find(hwndTabView); + if( it != m_tabs.end() ) + { + it->second->SetActiveConsole(hwndConsoleView); + if( m_activeTabView != it->second ) + { + int nCount = m_TabCtrl.GetItemCount(); + for(int i = 0; i < nCount; ++i) + { + if( m_TabCtrl.GetItem(i)->GetTabView() == hwndTabView ) + { + m_TabCtrl.SetCurSel(i); + break; + } + } + } + + this->ActivateApp(); + } +} + +void MainFrame::ActivateApp(void) +{ + m_activeTabView->SetAppActiveStatus(m_bAppActive); + + TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; + + if ((transparencySettings.transType == transAlpha) && + ((transparencySettings.byActiveAlpha != 255) || (transparencySettings.byInactiveAlpha != 255))) + { + if (m_bAppActive) + { + ::SetLayeredWindowAttributes(m_hWnd, RGB(0, 0, 0), transparencySettings.byActiveAlpha, LWA_ALPHA); + } + else + { + ::SetLayeredWindowAttributes(m_hWnd, RGB(0, 0, 0), transparencySettings.byInactiveAlpha, LWA_ALPHA); + } + + } + +#ifdef _USE_AERO + m_TabCtrl.SetAppActiveStatus(m_bAppActive); + m_TabCtrl.RedrawWindow(); +#endif + + if ((transparencySettings.transType == transGlass) && + (transparencySettings.byActiveAlpha != transparencySettings.byInactiveAlpha)) + { + m_activeTabView->Repaint(true); + } +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void MainFrame::ShowHideWindow(void) +{ + bool bQuake = g_settingsHandler->GetAppearanceSettings().stylesSettings.bQuake; + bool bActivate = true; + + DWORD dwActivateFlags = AW_ACTIVATE | AW_SLIDE; + DWORD dwHideFlags = AW_HIDE | AW_SLIDE; + + if( bQuake ) + { + switch( m_dockPosition ) + { + case dockNone: + // effect disabled ... + bQuake = false; + break; + case dockTL: + dwActivateFlags |= AW_VER_POSITIVE; + dwHideFlags |= AW_VER_NEGATIVE; + break; + case dockTR: + dwActivateFlags |= AW_VER_POSITIVE; + dwHideFlags |= AW_VER_NEGATIVE; + break; + case dockBL: + dwActivateFlags |= AW_VER_NEGATIVE; + dwHideFlags |= AW_VER_POSITIVE; + break; + case dockBR: + dwActivateFlags |= AW_VER_NEGATIVE; + dwHideFlags |= AW_VER_POSITIVE; + break; + } + } + + if( bQuake ) + { + if(!::IsWindowVisible(m_hWnd)) + { + ::AnimateWindow(m_hWnd, 300, dwActivateFlags); + } + else if(m_bAppActive) + { + ::AnimateWindow(m_hWnd, 300, dwHideFlags); + bActivate = false; + } + } + else + { + ShowWindow(this->IsIconic()?SW_RESTORE:SW_SHOW); + } + + if( bActivate ) + { + PostMessage(WM_ACTIVATEAPP, TRUE, 0); + + POINT cursorPos; + CRect windowRect; + + ::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; + + ::SetCursorPos(cursorPos.x, cursorPos.y); + ::SetForegroundWindow(m_hWnd); + } +} 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 : + { + ShowHideWindow(); + break; + } - POINT cursorPos; - CRect windowRect; + } - ::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; - - ::SetCursorPos(cursorPos.x, cursorPos.y); - ::SetForegroundWindow(m_hWnd); - break; - } - - } - - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -454,7 +623,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))) @@ -495,42 +664,9 @@ 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.get() == NULL) || (!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) +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) @@ -546,24 +682,6 @@ LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHa { 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; @@ -583,15 +701,31 @@ LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHa 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_activeTabView) + return 0; - if (m_activeView.get() != NULL) m_activeView->SetResizing(true); + m_activeTabView->SetResizing(true); +#if 0 + CPoint pointSize = m_activeView->GetCellSize(); + RECT *rectNew = (RECT *)lParam; - m_dwResizeWindowEdge = static_cast(wParam); + 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; +#endif return 0; } @@ -622,20 +756,23 @@ LRESULT MainFrame::OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM if (!(pWinPos->flags & SWP_NOMOVE)) { - // do nothing for maximized windows - if (IsZoomed()) return 0; + // do nothing for minimized or maximized windows + if (IsIconic() || IsZoomed()) return 0; - m_dockPosition = dockNone; - if (positionSettings.nSnapDistance >= 0) { + m_dockPosition = dockNone; + CRect rectMonitor; CRect rectDesktop; CRect rectWindow; 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); @@ -655,13 +792,13 @@ LRESULT MainFrame::OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM pWinPos->x = rectDesktop.left; nLR = 0; } - + if (pWinPos->x >= rectDesktop.right - rectWindow.Width() - positionSettings.nSnapDistance) { pWinPos->x = rectDesktop.right - rectWindow.Width(); nLR = 1; } - + if (pWinPos->y <= rectDesktop.top + positionSettings.nSnapDistance) { pWinPos->y = rectDesktop.top; @@ -681,12 +818,12 @@ LRESULT MainFrame::OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM } - if (m_activeView.get() != NULL) + 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); @@ -750,7 +887,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; @@ -796,8 +933,9 @@ LRESULT MainFrame::OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lPar // hopefully they don't happen often, so reload everything g_imageHandler->ReloadDesktopImages(); + // can't use Invalidate because full repaint is in order - m_activeView->Repaint(true); + m_activeTabView->Repaint(true); } return 0; @@ -810,12 +948,7 @@ 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); + AdjustWindowSize(ADJUSTSIZE_NONE); UpdateStatusBar(); return 0; } @@ -827,8 +960,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; } ////////////////////////////////////////////////////////////////////////////// @@ -838,32 +976,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; + std::shared_ptr tabView(itView->second); + std::shared_ptr consoleView = itView->second->GetActiveConsole(_T(__FUNCTION__)); + if (!consoleView) return 0; - shared_ptr consoleView(itView->second); WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; if (windowSettings.bUseConsoleTitle) { 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(*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); } @@ -882,7 +1015,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)) { @@ -897,14 +1030,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(*tabView, strTabTitle); } return 0; @@ -963,8 +1089,6 @@ LRESULT MainFrame::OnTrayNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, { case WM_RBUTTONUP : { - //if (m_bPopupMenuDisabled) return 0; - CPoint posCursor; ::GetCursorPos(&posCursor); @@ -983,28 +1107,22 @@ LRESULT MainFrame::OnTrayNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, // we need this for the menu to close when clicking outside of it PostMessage(WM_NULL, 0, 0); - + return 0; - } - + } + case WM_LBUTTONDOWN : { - // TODO: handle -// m_bHideWindow = false; -// ShowHideWindow(); - ::SetForegroundWindow(m_hWnd); + ShowHideWindow(); return 0; } - + case WM_LBUTTONDBLCLK : { - // TODO: handle -// m_bHideWindow = !m_bHideWindow; -// ShowHideWindow(); -// ::SetForegroundWindow(m_hWnd); + ShowHideWindow(); return 0; } - + default : return 0; } } @@ -1023,13 +1141,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); } @@ -1037,30 +1155,36 @@ 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); +#ifdef _USE_AERO + m_taskBarList.SelectTab(m_activeTabView->GetActiveConsole(_T(__FUNCTION__)).get(), m_hWnd); +#endif } else { - m_activeView = shared_ptr(); + m_activeTabView = std::shared_ptr(); } } if (appearanceSettings.stylesSettings.bTrayIcon) SetTrayIcon(NIM_MODIFY); - - if (appearanceSettings.windowSettings.bUseTabTitles && (m_activeView.get() != NULL)) + + if (appearanceSettings.windowSettings.bUseTabTitles && m_activeTabView) { - SetWindowText(m_activeView->GetTitle()); + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + SetWindowText(activeConsoleView->GetTitle()); + } } bHandled = FALSE; @@ -1089,12 +1213,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) { - CreateNewConsole(0); + + // I prefer choose my console with the good environment ... + // CreateNewConsole(0); + + 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 { @@ -1111,7 +1245,8 @@ LRESULT MainFrame::OnTabMiddleClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandl LRESULT MainFrame::OnRebarHeightChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { - AdjustWindowSize(false); + TRACE(L"MainFrame::OnRebarHeightChanged\n"); + AdjustWindowSize(ADJUSTSIZE_WINDOW); return 0; } @@ -1215,10 +1350,11 @@ LRESULT MainFrame::OnPrevTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl* ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnNextView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - PostMessage(WM_CLOSE); - return 0; + if( m_activeTabView ) + m_activeTabView->NextView(); + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1226,13 +1362,11 @@ LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnPrevView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; - - m_activeView->Paste(); - - return 0; + if( m_activeTabView ) + m_activeTabView->PrevView(); + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1240,13 +1374,12 @@ LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnCloseView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; - - m_activeView->Copy(); - - return 0; + if( m_activeTabView ) + m_activeTabView->CloseView(); + ::SetForegroundWindow(m_hWnd); + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1254,13 +1387,12 @@ LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnSplitHorizontally(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; - - m_activeView->ClearSelection(); - - return 0; + if( m_activeTabView ) + m_activeTabView->SplitHorizontally(); + ::SetForegroundWindow(m_hWnd); + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1268,13 +1400,12 @@ LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnSplitVertically(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; - - m_activeView->Paste(); - - return 0; + if( m_activeTabView ) + m_activeTabView->SplitVertically(); + ::SetForegroundWindow(m_hWnd); + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1282,13 +1413,14 @@ LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; - - m_activeView->GetConsoleHandler().StopScrolling(); - - return 0; + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->Group(true); + } + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1296,45 +1428,173 @@ LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnUngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->Group(false); + } + return 0; +} - DlgRenameTab dlg(m_activeView->GetTitle()); +////////////////////////////////////////////////////////////////////////////// - if (dlg.DoModal() == IDOK) - { - WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; - - m_activeView->SetTitle(dlg.m_strTabName); - CString strTabTitle(dlg.m_strTabName); +////////////////////////////////////////////////////////////////////////////// - if (windowSettings.bShowCommandInTabs) strTabTitle += m_activeView->GetConsoleCommand(); +LRESULT MainFrame::OnGroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + m_activeTabView->Group(true); + return 0; +} - // 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); - if (windowSettings.bUseTabTitles) SetWindowText(m_activeView->GetTitle()); - } +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnUngroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + m_activeTabView->Group(false); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + PostMessage(WM_CLOSE); return 0; } ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + PasteToConsoles(); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + activeConsoleView->Copy(); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + activeConsoleView->SelectAll(); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + activeConsoleView->ClearSelection(); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + PasteToConsoles(); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + activeConsoleView->GetConsoleHandler().StopScrolling(); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (!m_activeTabView) return 0; + + DlgRenameTab dlg(m_activeTabView->GetTitle()); + + if (dlg.DoModal() == IDOK) + { + m_activeTabView->SetTitle(dlg.m_strTabName); + + this->PostMessage( + UM_UPDATE_TITLES, + reinterpret_cast(m_activeTabView->m_hWnd), + 0); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeTabView) return 0; DlgSettingsMain dlg; @@ -1366,10 +1626,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; @@ -1381,10 +1641,13 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn SetZOrder(g_settingsHandler->GetAppearanceSettings().positionSettings.zOrder); - m_activeView->InitializeScrollbars(); - m_activeView->RecreateOffscreenBuffers(); - AdjustWindowSize(false); - m_activeView->Repaint(true); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->InitializeScrollbars(); + } + + ConsoleView::RecreateFont(); + AdjustWindowSize(ADJUSTSIZE_WINDOW); } RegisterGlobalHotkeys(); @@ -1447,13 +1710,17 @@ 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) - { - m_activeView->SetConsoleWindowVisible(!m_activeView->GetConsoleWindowVisible()); - UISetCheck(ID_VIEW_CONSOLE, m_activeView->GetConsoleWindowVisible() ? TRUE : FALSE); - } + if (m_activeTabView) + { + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + activeConsoleView->SetConsoleWindowVisible(!activeConsoleView->GetConsoleWindowVisible()); + UISetCheck(ID_VIEW_CONSOLE, activeConsoleView->GetConsoleWindowVisible() ? TRUE : FALSE); + } + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1475,11 +1742,16 @@ 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_activeTabView) + { + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + activeConsoleView->DumpBuffer(); + } + } - m_activeView->DumpBuffer(); - - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1501,23 +1773,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) @@ -1537,149 +1792,48 @@ 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); - } } -*/ ////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -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& strCmdLineInitialDir /*= wstring(L"")*/, const wstring& strCmdLineInitialCmd /*= wstring(L"")*/) { if (dwTabIndex >= g_settingsHandler->GetTabSettings().tabDataVector.size()) return false; - DWORD dwRows = g_settingsHandler->GetConsoleSettings().dwRows; - DWORD dwColumns = g_settingsHandler->GetConsoleSettings().dwColumns; + MutexLock tabMapLock(m_tabsMutex); - 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; - } + std::shared_ptr tabData = g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]; - shared_ptr consoleView(new ConsoleView(*this, dwTabIndex, strStartupDir, strStartupCmd, strDbgCmdLine, dwRows, dwColumns)); + std::shared_ptr tabView(new TabView(*this, tabData, strCmdLineInitialDir, strCmdLineInitialCmd)); - HWND hwndConsoleView = consoleView->Create( + HWND hwndTabView = tabView->Create( m_hWnd, rcDefault, NULL, - WS_CHILD | WS_VISIBLE,// | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - 0); + WS_CHILD | WS_VISIBLE); - if (hwndConsoleView == NULL) + if (hwndTabView == NULL) { - CString strMessage; - - // copied from ConsoleView::OnCreate - wstring strShell; - shared_ptr tabData = g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]; - 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_tabs.size() > 1) + { + CRect clientRect(0, 0, 0, 0); + tabView->AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); + 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); @@ -1695,8 +1849,10 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir void MainFrame::CloseTab(CTabViewTabItem* pTabItem) { - if (!pTabItem) return; - CloseTab(pTabItem->GetTabView()); + MutexLock viewMapLock(m_tabsMutex); + if (!pTabItem) return; + if (m_tabs.size() <= 1) return; + CloseTab(pTabItem->GetTabView()); } ////////////////////////////////////////////////////////////////////////////// @@ -1704,25 +1860,56 @@ 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(hwndTabView); + if (m_activeTabView == it->second) m_activeTabView.reset(); + it->second->DestroyWindow(); + m_tabs.erase(it); - RemoveTab(hwndConsoleView); - if (m_activeView.get() == it->second.get()) m_activeView.reset(); - it->second->DestroyWindow(); - m_views.erase(it); + 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() == 1) && - m_bTabsVisible && - (g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) + if (m_tabs.size() == 0) PostMessage(WM_CLOSE); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void MainFrame::UpdateTabTitle(HWND hwndTabView, CString& strTabTitle) +{ + // we always set the tool tip text to the complete, untrimmed title + UpdateTabToolTip(hwndTabView, strTabTitle); + + WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; + + if + ( + (windowSettings.dwTrimTabTitles > 0) + && + (windowSettings.dwTrimTabTitles > windowSettings.dwTrimTabTitlesRight) + && + (strTabTitle.GetLength() > static_cast(windowSettings.dwTrimTabTitles)) + ) { - ShowTabs(FALSE); + strTabTitle = strTabTitle.Left(windowSettings.dwTrimTabTitles - windowSettings.dwTrimTabTitlesRight) + CString(L"...") + strTabTitle.Right(windowSettings.dwTrimTabTitlesRight); } - - if (m_views.size() == 0) PostMessage(WM_CLOSE); + + UpdateTabText(hwndTabView, strTabTitle); } ////////////////////////////////////////////////////////////////////////////// @@ -1736,33 +1923,51 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) tabsMenu.CreateMenu(); // build tabs menu - TabDataVector& tabDataVector = g_settingsHandler->GetTabSettings().tabDataVector; - TabDataVector::iterator it = tabDataVector.begin(); - DWORD dwId = ID_NEW_TAB_1; + TabDataVector& tabDataVector = g_settingsHandler->GetTabSettings().tabDataVector; + WORD wId = ID_NEW_TAB_1; - for (it; it != tabDataVector.end(); ++it, ++dwId) + for (auto it = tabDataVector.begin(); it != tabDataVector.end(); ++it, ++wId) { CMenuItemInfo subMenuItem; -/* - ICONINFO iconInfo; - BITMAP bmp; - ::GetIconInfo(tabDataVector[dwId-ID_NEW_TAB_1]->tabSmallIcon, &iconInfo); - ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp); -*/ + auto hotK = g_settingsHandler->GetHotKeys().commands.get().find(wId); - 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()); + std::wstring strTitle = (*it)->strTitle; + if( hotK != g_settingsHandler->GetHotKeys().commands.get().end() ) + { + strTitle += L"\t"; + strTitle += hotK->get()->GetHotKeyName(); + } + + subMenuItem.fMask = MIIM_STRING | MIIM_ID; + subMenuItem.wID = wId; + subMenuItem.dwTypeData = const_cast(strTitle.c_str()); + subMenuItem.cch = static_cast(strTitle.length()); + + tabsMenu.InsertMenuItem(wId-ID_NEW_TAB_1, TRUE, &subMenuItem); - tabsMenu.InsertMenuItem(dwId-ID_NEW_TAB_1, TRUE, &subMenuItem); -// tabsMenu.SetMenuItemBitmaps(dwId, MF_BYCOMMAND, iconInfo.hbmColor, NULL); + // create menu icons with proper transparency (thanks to chrisz for the patch) + CIcon tabSmallIcon(Helpers::LoadTabIcon(false, (*it)->bUseDefaultIcon, (*it)->strIcon, (*it)->strShell)); + + // destroy icon bitmap + if (!(*it)->menuBitmap.IsNull()) (*it)->menuBitmap.DeleteObject(); + + if (!tabSmallIcon.IsNull()) + { + CDC dc; + + (*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); + } + + if (!(*it)->menuBitmap.IsNull()) + { + tabsMenu.SetMenuItemBitmaps(wId, MF_BYCOMMAND, (*it)->menuBitmap, NULL); + } } // set tabs menu as popup submenu @@ -1775,6 +1980,9 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) mainMenu.SetMenuItemInfo(ID_FILE_NEW_TAB, FALSE, &menuItem); } + + // create jumplist + JumpList::CreateList(g_settingsHandler->GetTabSettings().tabDataVector); } ////////////////////////////////////////////////////////////////////////////// @@ -1784,12 +1992,52 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) void MainFrame::UpdateStatusBar() { - CString strRowsCols; + static CString strCAPS(LPCTSTR(IDPANE_CAPS_INDICATOR)); + static CString strNUM (LPCTSTR(IDPANE_NUM_INDICATOR )); + static CString strSCRL(LPCTSTR(IDPANE_SCRL_INDICATOR)); + + UISetText(1, (GetKeyState(VK_CAPITAL) & 1) ? strCAPS : L""); + UISetText(2, (GetKeyState(VK_NUMLOCK) & 1) ? strNUM : L""); + UISetText(3, (GetKeyState(VK_SCROLL) & 1) ? strSCRL : L""); - strRowsCols.Format(IDPANE_ROWS_COLUMNS, m_dwRows, m_dwColumns); - UISetText(1, strRowsCols); + wchar_t strSelection [16] = L""; + wchar_t strColsRows [16] = L""; + wchar_t strBufColsRows [16] = L""; + wchar_t strPid [16] = L""; - UIUpdateStatusBar(); + if (m_activeTabView) + { + std::shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + SharedMemory& consoleParams = activeConsoleView->GetConsoleHandler().GetConsoleParams(); + + DWORD dwSelectionSize = activeConsoleView->GetSelectionSize(); + if( dwSelectionSize ) + _snwprintf_s(strSelection, ARRAYSIZE(strSelection), _TRUNCATE, L"%lu", dwSelectionSize); + + _snwprintf_s(strColsRows, ARRAYSIZE(strColsRows), _TRUNCATE, L"%lux%lu", + consoleParams->dwColumns, + consoleParams->dwRows); + _snwprintf_s(strPid, ARRAYSIZE(strPid), _TRUNCATE, L"%lu", + activeConsoleView->GetConsoleHandler().GetConsolePid()); + _snwprintf_s(strBufColsRows, ARRAYSIZE(strBufColsRows), _TRUNCATE, L"%lux%lu", + consoleParams->dwBufferColumns ? consoleParams->dwBufferColumns : consoleParams->dwColumns, + consoleParams->dwBufferRows ? consoleParams->dwBufferRows : consoleParams->dwRows); + + 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); + } + } + + UISetText(4, strPid); + UISetText(5, strSelection); + UISetText(6, strColsRows); + UISetText(7, strBufColsRows); + + UIUpdateStatusBar(); } ////////////////////////////////////////////////////////////////////////////// @@ -1804,16 +2052,18 @@ 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; if (!stylesSettings.bTaskbarButton) { - // remove minimize button - dwStyle &= ~WS_MINIMIZEBOX; -// dwExStyle |= WS_EX_TOOLWINDOW; - dwExStyle &= ~WS_EX_APPWINDOW; + if (!stylesSettings.bTrayIcon) + { + // remove minimize button + dwStyle &= ~WS_MINIMIZEBOX; + } + dwExStyle &= ~WS_EX_APPWINDOW; } if (stylesSettings.bBorder) dwStyle |= WS_BORDER; @@ -1933,49 +2183,15 @@ 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_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 { - 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()) @@ -2006,7 +2222,7 @@ void MainFrame::ShowMenu(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowMenu = m_bMenuVisible ? true : false; UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2027,7 +2243,7 @@ void MainFrame::ShowToolbar(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowToolbar = m_bToolbarVisible? true : false; UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2046,7 +2262,7 @@ void MainFrame::ShowStatusbar(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowStatusbar = m_bStatusBarVisible? true : false; UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2078,7 +2294,7 @@ void MainFrame::ShowTabs(BOOL bShow) } UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2092,26 +2308,28 @@ void MainFrame::ResizeWindow() CRect rectWindow; GetWindowRect(&rectWindow); - CRect rectClient; - GetClientRect(&rectClient); - DWORD dwWindowWidth = rectWindow.Width(); DWORD dwWindowHeight= rectWindow.Height(); +#ifdef _DEBUG + CRect rectClient; + GetClientRect(&rectClient); + TRACE(L"old dims: %ix%i\n", m_dwWindowWidth, m_dwWindowHeight); TRACE(L"new dims: %ix%i\n", dwWindowWidth, dwWindowHeight); TRACE(L"client dims: %ix%i\n", rectClient.Width(), rectClient.Height()); +#endif if ((dwWindowWidth != m_dwWindowWidth) || (dwWindowHeight != m_dwWindowHeight)) { - AdjustWindowSize(true, false); + AdjustWindowSize(ADJUSTSIZE_WINDOW); } SendMessage(WM_NULL, 0, 0); m_dwResizeWindowEdge = WMSZ_BOTTOM; - if (m_activeView.get() != NULL) m_activeView->SetResizing(false); + if (m_activeTabView) m_activeTabView->SetResizing(false); } ////////////////////////////////////////////////////////////////////////////// @@ -2119,158 +2337,65 @@ void MainFrame::ResizeWindow() ////////////////////////////////////////////////////////////////////////////// -void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= false*/) +void MainFrame::AdjustWindowSize(ADJUSTSIZE as) { + TRACE(L"AdjustWindowSize\n"); CRect clientRect(0, 0, 0, 0); - if (bResizeConsole) + if (as != ADJUSTSIZE_NONE) { - if (bMaxOrRestore) - { - GetClientRect(&clientRect); - - // adjust for the toolbar height - CReBarCtrl rebar(m_hWndToolBar); -// clientRect.top += rebar.GetBarHeight() - 4; - 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.get() == NULL) return; - - // 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; + if (!m_activeTabView) return; - it->second->SetWindowPos( - 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, !bMaxOrRestore); - } - } - else - { - if (m_activeView.get() == NULL) return; - CRect maxClientRect; - m_activeView->GetMaxRect(maxClientRect); - m_activeView->GetRect(clientRect); + m_activeTabView->AdjustRectAndResize(as, clientRect, m_dwResizeWindowEdge); - if (clientRect.Width() > maxClientRect.Width()) clientRect.right = maxClientRect.right; - if (clientRect.Height() > maxClientRect.Height()) clientRect.bottom = maxClientRect.bottom; - } - - AdjustWindowRect(clientRect); - -// TRACE(L"AdjustWindowSize: %ix%i\n", clientRect.Width(), clientRect.Height()); - - SetWindowPos( - 0, - 0, - 0, - clientRect.Width(), - clientRect.Height() + 4, - SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - - // update window width and height - CRect rectWindow; - - GetWindowRect(&rectWindow); -// TRACE(L"AdjustWindowSize 2: %ix%i\n", rectWindow.Width(), rectWindow.Height()); - m_dwWindowWidth = rectWindow.Width(); - m_dwWindowHeight= rectWindow.Height(); - -/* - CRect clientRect; - GetClientRect(&clientRect); - - 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 - } - - if (bResizeConsole) - { -// AdjustAndResizeConsoleView(clientRect); - - // adjust the active view - if (m_activeView.get() == NULL) return; - - m_activeView->AdjustRectAndResize(clientRect); - // 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) + MutexLock viewMapLock(m_tabsMutex); + + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) { - if (it->second->m_hWnd == m_activeView->m_hWnd) 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); - - it->second->AdjustRectAndResize(clientRect); + + it->second->AdjustRectAndResize(as, clientRect, m_dwResizeWindowEdge); } } else { - if (m_activeView.get() == NULL) return; + if (!m_activeTabView) return; - m_activeView->GetRect(clientRect); + 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()); 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 CRect rectWindow; GetWindowRect(&rectWindow); + TRACE(L"AdjustWindowSize 2: %ix%i\n", rectWindow.Width(), rectWindow.Height()); m_dwWindowWidth = rectWindow.Width(); m_dwWindowHeight= rectWindow.Height(); -*/ + + SetMargins(); } ////////////////////////////////////////////////////////////////////////////// @@ -2278,64 +2403,164 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal ////////////////////////////////////////////////////////////////////////////// -void MainFrame::SetTransparency() +void MainFrame::SetMargins(void) { - // set transparency - TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; - - switch (transparencySettings.transType) - { - case transAlpha : - - // if Console is pinned to the desktop window, wee need to set it as top-level window temporarily - if (m_zOrder == zorderDesktop) SetParent(NULL); - - if ((transparencySettings.byActiveAlpha == 255) && - (transparencySettings.byInactiveAlpha == 255)) - { - - break; - } - - SetWindowLong( - GWL_EXSTYLE, - GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED); - - ::SetLayeredWindowAttributes( - m_hWnd, - 0, - transparencySettings.byActiveAlpha, - LWA_ALPHA); - - // back to desktop-pinned mode, if needed - if (m_zOrder == zorderDesktop) SetParent(GetDesktopWindow()); - - break; - - case transColorKey : - { - SetWindowLong( - GWL_EXSTYLE, - GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED); - - ::SetLayeredWindowAttributes( - m_hWnd, - transparencySettings.crColorKey, - transparencySettings.byActiveAlpha, - LWA_COLORKEY); - - break; - } - - default : - { - SetWindowLong( - GWL_EXSTYLE, - GetWindowLong(GWL_EXSTYLE) & ~WS_EX_LAYERED); - } - + CReBarCtrl rebar(m_hWndToolBar); + 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(); +} - } +void MainFrame::SetTransparency() +{ + // set transparency + TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; + + // RAZ + SetWindowLong( + GWL_EXSTYLE, + GetWindowLong(GWL_EXSTYLE) & ~WS_EX_LAYERED); + +#ifdef _USE_AERO + StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + + BOOL fEnabled = FALSE; + DwmIsCompositionEnabled(&fEnabled); + if( fEnabled ) + { + if( transparencySettings.transType != transGlass ) + { + // there is a side effect whith glass into client area and no caption (and no resizable) + // blur is not applied, the window is transparent ... + if( !stylesSettings.bCaption && !stylesSettings.bResizable ) + { + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE; + bb.fEnable = FALSE; + bb.hRgnBlur = NULL; + ::DwmEnableBlurBehindWindow(m_hWnd, &bb); + + fEnabled = FALSE; + } + else + { + if( transparencySettings.transType == transColorKey ) + { + MARGINS m = {0, 0, 0, 0}; + ::DwmExtendFrameIntoClientArea(m_hWnd, &m); + } + else + { + ::DwmExtendFrameIntoClientArea(m_hWnd, &m_Margins); + } + } + } + } +#endif + + switch (transparencySettings.transType) + { + case transAlpha: + // if Console is pinned to the desktop window, wee need to set it as top-level window temporarily + if (m_zOrder == zorderDesktop) SetParent(NULL); + + if ((transparencySettings.byActiveAlpha == 255) && + (transparencySettings.byInactiveAlpha == 255)) + { + + break; + } + + SetWindowLong( + GWL_EXSTYLE, + GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED); + + ::SetLayeredWindowAttributes( + m_hWnd, + 0, + transparencySettings.byActiveAlpha, + LWA_ALPHA); + + // back to desktop-pinned mode, if needed + if (m_zOrder == zorderDesktop) SetParent(GetDesktopWindow()); + + break; + + case transColorKey : + { +#ifdef _USE_AERO + // under VISTA/Windows 7 color key transparency replace aero glass by black + fEnabled = FALSE; +#endif + + SetWindowLong( + GWL_EXSTYLE, + GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED); + + ::SetLayeredWindowAttributes( + m_hWnd, + transparencySettings.crColorKey, + transparencySettings.byActiveAlpha, + LWA_COLORKEY); + + break; + } + + case transGlass : + { +#ifdef _USE_AERO + if( fEnabled ) + { + // there is a side effect whith glass into client area and no caption (and no resizable) + // blur is not applied, the window is transparent ... + if( !stylesSettings.bCaption && !stylesSettings.bResizable ) + { + 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); + } + else + { + MARGINS m = {-1,-1,-1,-1}; + ::DwmExtendFrameIntoClientArea(m_hWnd, &m); + } + } +#endif + + break; + } + } + +#ifdef _USE_AERO + aero::SetAeroGlassActive(fEnabled != FALSE); + m_ATB.Invalidate(TRUE); + m_TabCtrl.Invalidate(TRUE); +#endif } ////////////////////////////////////////////////////////////////////////////// @@ -2345,15 +2570,13 @@ void MainFrame::SetTransparency() void MainFrame::CreateAcceleratorTable() { - HotKeys& hotKeys = g_settingsHandler->GetHotKeys(); - HotKeys::CommandsSequence::iterator it = hotKeys.commands.begin(); + HotKeys& hotKeys = g_settingsHandler->GetHotKeys(); + std::unique_ptr accelTable(new ACCEL[hotKeys.commands.size()]); + int nAccelCount = 0; - shared_array accelTable(new ACCEL[hotKeys.commands.size()]); - int nAccelCount = 0; - - for (; it != hotKeys.commands.end(); ++it) + for (auto it = hotKeys.commands.begin(); it != hotKeys.commands.end(); ++it) { - shared_ptr c(*it); + std::shared_ptr c(*it); if ((*it)->accelHotkey.cmd == 0) continue; if ((*it)->accelHotkey.key == 0) continue; @@ -2421,12 +2644,14 @@ void MainFrame::UnregisterGlobalHotkeys() void MainFrame::CreateStatusBar() { m_hWndStatusBar = m_statusBar.Create(*this); - UIAddStatusBar(m_hWndStatusBar); +#ifdef _USE_AERO + aero::Subclass(m_ASB, m_hWndStatusBar); +#endif + UIAddStatusBar(m_hWndStatusBar); + + int arrPanes[] = { ID_DEFAULT_PANE, IDPANE_CAPS_INDICATOR, IDPANE_NUM_INDICATOR, IDPANE_SCRL_INDICATOR, IDPANE_PID_INDICATOR, IDPANE_SELECTION, IDPANE_COLUMNS_ROWS, IDPANE_BUF_COLUMNS_ROWS}; - int arrPanes[] = { ID_DEFAULT_PANE, IDPANE_ROWS_COLUMNS }; - - m_statusBar.SetPanes(arrPanes, sizeof(arrPanes)/sizeof(int), false); - m_statusBar.SetPaneWidth(IDPANE_ROWS_COLUMNS, 50); + m_statusBar.SetPanes(arrPanes, sizeof(arrPanes)/sizeof(int), true); } ////////////////////////////////////////////////////////////////////////////// @@ -2459,3 +2684,63 @@ 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; + std::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(); + } +} + +void MainFrame::SendTextToConsole(const wchar_t* pszText) +{ + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->SendTextToConsole(pszText); + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnCopyData(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) +{ + COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam; + if (!cds) return 0; + + vector startupTabs; + vector startupCmds; + vector startupDirs; + int nMultiStartSleep; + + wstring ignoreTitle; + + ParseCommandLine((LPCTSTR)cds->lpData, ignoreTitle, startupTabs, startupDirs, startupCmds, nMultiStartSleep); + CreateInitialTabs(startupTabs, startupCmds, startupDirs, nMultiStartSleep); + + return 0; +} diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 8e20263e..02d1f67c 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -1,6 +1,7 @@ #pragma once -#include "AnimationWindow.h" +#include "TaskBarList.h" + ////////////////////////////////////////////////////////////////////////////// @@ -17,10 +18,8 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -class ConsoleView; - - -typedef map > ConsoleViewMap; +class TabView; +typedef map > TabViewMap; ////////////////////////////////////////////////////////////////////////////// @@ -33,28 +32,45 @@ class MainFrame public: DECLARE_FRAME_WND_CLASS(L"Console_2_Main", IDR_MAINFRAME) +#ifdef _USE_AERO + aero::CCommandBarCtrl m_CmdBar; + TaskBarList m_taskBarList; + void OnComposition() + { + this->SetTransparency(); + } +#else CCommandBarCtrl m_CmdBar; +#endif MainFrame ( - const wstring strWindowTitle, - const vector& startupTabs, - const vector& startupDirs, - const vector& startupCmds, - int nMultiStartSleep, - const wstring& strDbgCmdLine + LPCTSTR lpstrCmdLine ); virtual BOOL PreTranslateMessage(MSG* pMsg); virtual BOOL OnIdle(); BEGIN_UPDATE_UI_MAP(MainFrame) + UPDATE_ELEMENT(ID_FILE_CLOSE_TAB, UPDUI_MENUPOPUP) + UPDATE_ELEMENT(ID_EDIT_COPY, UPDUI_MENUPOPUP) + UPDATE_ELEMENT(ID_EDIT_SELECT_ALL, 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) UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_CONSOLE, UPDUI_MENUPOPUP) + UPDATE_ELEMENT(1, UPDUI_STATUSBAR) + UPDATE_ELEMENT(2, UPDUI_STATUSBAR) + UPDATE_ELEMENT(3, UPDUI_STATUSBAR) + UPDATE_ELEMENT(4, UPDUI_STATUSBAR) + UPDATE_ELEMENT(5, UPDUI_STATUSBAR) + UPDATE_ELEMENT(6, UPDUI_STATUSBAR) + UPDATE_ELEMENT(7, UPDUI_STATUSBAR) + END_UPDATE_UI_MAP() BEGIN_MSG_MAP(MainFrame) @@ -65,7 +81,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) @@ -83,20 +99,34 @@ class MainFrame MESSAGE_HANDLER(UM_SHOW_POPUP_MENU, OnShowPopupMenu) MESSAGE_HANDLER(UM_START_MOUSE_DRAG, OnStartMouseDrag) MESSAGE_HANDLER(UM_TRAY_NOTIFY, OnTrayNotify) + MESSAGE_HANDLER(WM_COPYDATA, OnCopyData) + 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) - 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_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) + COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnEditSelectAll) COMMAND_ID_HANDLER(ID_EDIT_CLEAR_SELECTION, OnEditClearSelection) COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnEditPaste) COMMAND_ID_HANDLER(ID_EDIT_STOP_SCROLLING, OnEditStopScrolling) @@ -110,7 +140,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() @@ -129,7 +159,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); @@ -161,10 +190,21 @@ 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*/); LRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -183,17 +223,22 @@ class MainFrame public: -// shared_ptr GetActiveView(); - void AdjustWindowRect(CRect& rect); -// void AdjustAndResizeConsoleView(CRect& rectView); + void AdjustWindowSize(ADJUSTSIZE as); + void CloseTab(HWND hwndTabView); + void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); + void PasteToConsoles(); + void SendTextToConsole(const wchar_t* pszText); + bool GetAppActiveStatus(void) const { return this->m_bAppActive; } + void ActivateApp(HWND hwndTabView, HWND hwndConsoleView); private: - bool CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir = wstring(L""), const wstring& strStartupCmd = wstring(L""), const wstring& strDbgCmdLine = wstring(L"")); + void ActivateApp(); + bool CreateNewConsole(DWORD dwTabIndex, const wstring& strCmdLineInitialDir = wstring(L""), const wstring& strCmdLineInitialCmd = wstring(L"")); void CloseTab(CTabViewTabItem* pTabItem); - void CloseTab(HWND hwndConsoleView); + void UpdateTabTitle(HWND hwndTabView, CString& strTabTitle); void UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu); void UpdateStatusBar(); void SetWindowStyles(); @@ -209,25 +254,34 @@ class MainFrame void ShowStatusbar(BOOL bShow); void ResizeWindow(); - void AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore = false); + void SetMargins(); void SetTransparency(); void CreateAcceleratorTable(); void RegisterGlobalHotkeys(); void UnregisterGlobalHotkeys(); void CreateStatusBar(); BOOL SetTrayIcon(DWORD dwMessage); + void ShowHideWindow(); - private: + public: + LRESULT CreateInitialTabs + ( + vector startupTabs, + vector startupCmds, + vector startupDirs, + int nMultiStartSleep + ); + LRESULT OnCopyData(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/); bool m_bOnCreateDone; - const vector& m_startupTabs; - const vector& m_startupDirs; - const vector& m_startupCmds; + private: + vector m_startupTabs; + vector m_startupDirs; + vector m_startupCmds; int m_nMultiStartSleep; - wstring m_strDbgCmdLine; - shared_ptr m_activeView; + std::shared_ptr m_activeTabView; BOOL m_bMenuVisible; BOOL m_bToolbarVisible; @@ -238,8 +292,8 @@ class MainFrame ZOrder m_zOrder; CPoint m_mousedragOffset; - ConsoleViewMap m_views; - Mutex m_viewsMutex; + TabViewMap m_tabs; + Mutex m_tabsMutex; CMenu m_tabsMenu; @@ -249,13 +303,11 @@ class MainFrame CString m_strCmdLineWindowTitle; CString m_strWindowTitle; - DWORD m_dwRows; - DWORD m_dwColumns; - DWORD m_dwWindowWidth; DWORD m_dwWindowHeight; DWORD m_dwResizeWindowEdge; + bool m_bAppActive; bool m_bRestoringWindow; CRect m_rectRestoredWnd; @@ -263,10 +315,7 @@ class MainFrame CAccelerator m_acceleratorTable; CMultiPaneStatusBarCtrl m_statusBar; - CDC m_dcOffscreen; - CDC m_dcText; - - shared_ptr m_animationWindow; + MARGINS m_Margins; }; diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index b15ead64..1aed37ef 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -4,6 +4,8 @@ #include "Cursors.h" #include "PageSettingsTabs1.h" +extern std::shared_ptr g_settingsHandler; + ////////////////////////////////////////////////////////////////////////////// @@ -18,8 +20,12 @@ PageSettingsTabs1::PageSettingsTabs1() : m_tabData() , m_strTitle(L"") , m_strIcon(L"") +, m_bUseDefaultIcon(false) , m_strShell(L"") , m_strInitialDir(L"") +, m_bRunAsUser(false) +, m_strUser(L"") +, m_bNetOnly(false) { } @@ -39,6 +45,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)); @@ -73,6 +80,8 @@ LRESULT PageSettingsTabs1::OnCtlColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM m_staticCursorColor.GetClientRect(&rect); dc.FillRect(&rect, brush); + + SetCursor(); return 0; } @@ -95,11 +104,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; +} + ////////////////////////////////////////////////////////////////////////////// @@ -187,3 +202,201 @@ LRESULT PageSettingsTabs1::OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*wI ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// + +LRESULT PageSettingsTabs1::OnCheckboxClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + DoDataExchange(DDX_SAVE); + EnableControls(); + + GetParent().PostMessage(UM_TAB_ICON_CHANGED, 0, 0); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs1::EnableControls() +{ + BOOL bEnableEditIconCtrls = TRUE; + + if (m_bUseDefaultIcon) bEnableEditIconCtrls = FALSE; + + GetDlgItem(IDC_TAB_ICON).EnableWindow(bEnableEditIconCtrls); + GetDlgItem(IDC_BTN_BROWSE_ICON).EnableWindow(bEnableEditIconCtrls); + + GetDlgItem(IDC_TAB_USER).EnableWindow(m_bRunAsUser ? TRUE : FALSE); + GetDlgItem(IDC_CHECK_NET_ONLY).EnableWindow(m_bRunAsUser ? TRUE : FALSE); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs1::Load(std::shared_ptr& tabData) +{ + m_tabData = tabData; + + m_strTitle = m_tabData->strTitle.c_str(); + m_strIcon = m_tabData->strIcon.c_str(); + m_bUseDefaultIcon = m_tabData->bUseDefaultIcon; + + 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_bNetOnly = m_tabData->bNetOnly; + + 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_bUseDefaultIcon; + + m_tabData->strShell = m_strShell; + m_tabData->strInitialDir = m_strInitialDir; + m_tabData->bRunAsUser = m_bRunAsUser; + m_tabData->strUser = m_strUser; + m_tabData->bNetOnly = m_bNetOnly; + + m_tabData->dwCursorStyle = m_comboCursor.GetCurSel(); +} + +////////////////////////////////////////////////////////////////////////////// + +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 -= 12; + rectCursorAnim.right /= 2; + rectCursorAnim.bottom -= 8; + + m_cursor.reset(); + m_cursor = CursorFactory::CreateCursor( + m_hWnd, + true, + static_cast(m_comboCursor.GetCurSel()), + dc, + rectCursorAnim, + m_tabData->crCursorColor, + this); + + DrawCursor(); +} + +void PageSettingsTabs1::RedrawCharOnCursor(CDC& dc) +{ + CRect rectCursorAnim; + m_staticCursorAnim.GetClientRect(&rectCursorAnim); + + rectCursorAnim.right -= 12; + rectCursorAnim.right /= 2; + rectCursorAnim.bottom -= 8; + + rectCursorAnim.OffsetRect(4, 4); + + DrawCursor( + dc, + rectCursorAnim, + g_settingsHandler->GetConsoleSettings().consoleColors[0], + m_tabData->crCursorColor); +} + +void PageSettingsTabs1::DrawCursor() +{ + m_staticCursorAnim.RedrawWindow(); + + CClientDC dc(m_staticCursorAnim.m_hWnd); + CBrush brush(::CreateSolidBrush(RGB(0,0,0))); + + m_cursor->PrepareNext(); + + CRect rectCursorAnim; + m_staticCursorAnim.GetClientRect(&rectCursorAnim); + dc.FillRect(rectCursorAnim, brush); + + rectCursorAnim.right -= 12; + rectCursorAnim.right /= 2; + rectCursorAnim.bottom -= 8; + + rectCursorAnim.OffsetRect(4, 4); + + DrawCursor( + dc, + rectCursorAnim, + g_settingsHandler->GetConsoleSettings().consoleColors[7], + g_settingsHandler->GetConsoleSettings().consoleColors[0]); + + m_cursor->Draw(true); + m_cursor->BitBlt(dc, rectCursorAnim.left, rectCursorAnim.top); + + rectCursorAnim.OffsetRect(rectCursorAnim.Width() + 4, 0); + + DrawCursor( + dc, + rectCursorAnim, + g_settingsHandler->GetConsoleSettings().consoleColors[7], + g_settingsHandler->GetConsoleSettings().consoleColors[0]); + + m_cursor->Draw(false); + m_cursor->BitBlt(dc, rectCursorAnim.left, rectCursorAnim.top); +} + +void PageSettingsTabs1::DrawCursor(CDC& dc, const CRect& rectCursorAnim, COLORREF fg, COLORREF bg) +{ + CBrush brush(::CreateSolidBrush(bg)); + CPen pen(::CreatePen(PS_SOLID, 2, fg)); + + dc.FillRect(rectCursorAnim, brush); + + CRect rectChar(rectCursorAnim); + rectChar.DeflateRect(3, 3); + dc.SelectPen(pen); + dc.MoveTo(rectChar.left , rectChar.top ); + dc.LineTo(rectChar.right, rectChar.bottom); + dc.MoveTo(rectChar.right, rectChar.top ); + dc.LineTo(rectChar.left , rectChar.bottom); +} \ No newline at end of file diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index 8345d020..d89d61c8 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -1,6 +1,7 @@ - #pragma once +#include "Cursors.h" + ////////////////////////////////////////////////////////////////////////////// @@ -9,12 +10,14 @@ ////////////////////////////////////////////////////////////////////////////// #define UM_TAB_TITLE_CHANGED WM_USER + 0x2000 +#define UM_TAB_ICON_CHANGED WM_USER + 0x2001 ////////////////////////////////////////////////////////////////////////////// class PageSettingsTabs1 : public CDialogImpl , public CWinDataExchange + , public CursorCharDrawer { public: @@ -25,21 +28,29 @@ 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_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) + DDX_TEXT(IDC_TAB_USER, m_strUser) + DDX_CHECK(IDC_CHECK_NET_ONLY, m_bNetOnly) END_DDX_MAP() BEGIN_MSG_MAP(PageSettingsTabs1) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) -// MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 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) COMMAND_HANDLER(IDC_CURSOR_COLOR, BN_CLICKED, OnClickedCursorColor) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_ICON, OnBtnBrowseIcon) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_SHELL, OnClickedBtnBrowseShell) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_DIR, OnClickedBtnBrowseDir) - END_MSG_MAP() + COMMAND_ID_HANDLER(IDC_CHECK_DEFAULT_ICON, OnCheckboxClicked) + COMMAND_ID_HANDLER(IDC_CHECK_RUN_AS_USER, OnCheckboxClicked) + 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*/) @@ -49,25 +60,52 @@ 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*/); 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*/); LRESULT OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCheckboxClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); - public: + void EnableControls(); + + void Load(std::shared_ptr& tabData); + void Save(); + + const CString& GetTabTitle() const { return m_strTitle; } + const CString& GetTabIcon() const { return m_strIcon; } + const CString& GetTabShell() const { return m_strShell; } + const bool UseDefaultIcon() const { return m_bUseDefaultIcon; } + + virtual void RedrawCharOnCursor(CDC& dc); + +private: + void SetCursor(void); + void DrawCursor(void); + void DrawCursor(CDC& dc, const CRect& rectCursorAnim, COLORREF fg, COLORREF bg); - shared_ptr m_tabData; + private: + std::shared_ptr m_cursor; + std::shared_ptr m_tabData; + CStatic m_staticCursorAnim; CComboBox m_comboCursor; CStatic m_staticCursorColor; CString m_strTitle; CString m_strIcon; + bool m_bUseDefaultIcon; CString m_strShell; CString m_strInitialDir; + bool m_bRunAsUser; + CString m_strUser; + bool m_bNetOnly; +public: + LRESULT OnCbnSelchangeComboCursor(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/PageSettingsTabs2.cpp b/Console/PageSettingsTabs2.cpp index 87032b69..0affbc27 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) { } @@ -40,6 +40,8 @@ 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"Fit"); + m_comboBkPosition.AddString(L"Fill"); m_staticTintOpacity.Attach(GetDlgItem(IDC_TINT_OPACITY_VAL)); m_sliderTintOpacity.Attach(GetDlgItem(IDC_TINT_OPACITY)); @@ -249,3 +251,48 @@ void PageSettingsTabs2::EnableControls() } ////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs2::Load(std::shared_ptr& tabData) +{ + m_tabData = tabData; + + m_nBkType = static_cast(m_tabData->backgroundImageType); + m_strBkImage = m_tabData->imageData.strFilename.c_str(); + m_bRelative = m_tabData->imageData.bRelative; + m_bExtend = m_tabData->imageData.bExtend; + + 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); + + m_tabData->backgroundImageType = static_cast(m_nBkType); + 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 10ca816f..5c3ed751 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) @@ -59,9 +59,12 @@ class PageSettingsTabs2 void UpdateSliderText(); void EnableControls(); - public: + void Load(std::shared_ptr& tabData); + void Save(); + + private: - shared_ptr m_tabData; + std::shared_ptr m_tabData; CComboBox m_comboBkPosition; CTrackBarCtrl m_sliderTintOpacity; @@ -73,8 +76,8 @@ class PageSettingsTabs2 int m_nBkType; CString m_strBkImage; - int m_nRelative; - int m_nExtend; + bool m_bRelative; + bool m_bExtend; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/SelectionHandler.cpp b/Console/SelectionHandler.cpp index f8a4cd17..3f0bdf41 100644 --- a/Console/SelectionHandler.cpp +++ b/Console/SelectionHandler.cpp @@ -15,38 +15,43 @@ SelectionHandler::SelectionHandler( const CWindow& consoleView, +#ifndef _USE_AERO const CDC& dcConsoleView, const CRect& rectConsoleView, +#endif //!_USE_AERO ConsoleHandler& consoleHandler, SharedMemory& consoleParams, - SharedMemory& consoleInfo, + SharedMemory& consoleInfo, SharedMemory& consoleCopyInfo, int nCharWidth, - int nCharHeight) + int nCharHeight, + int nVInsideBorder, + int nHInsideBorder) : m_consoleView(consoleView) +#ifndef _USE_AERO , m_dcSelection(::CreateCompatibleDC(NULL)) -//, m_bmpSelection(::CreateCompatibleBitmap(dcConsoleView, rectConsoleView.Width(), rectConsoleView.Height())) , m_bmpSelection(NULL) , m_rectConsoleView(rectConsoleView) +, m_paintBrush(::CreateSolidBrush(g_settingsHandler->GetAppearanceSettings().stylesSettings.crSelectionColor)) +, m_backgroundBrush(::CreateSolidBrush(RGB(0, 0, 0))) +#endif //!_USE_AERO , m_nCharWidth(nCharWidth) , m_consoleHandler(consoleHandler) , m_consoleParams(consoleParams) , m_consoleInfo(consoleInfo) , m_consoleCopyInfo(consoleCopyInfo) , m_nCharHeight(nCharHeight) -, m_paintBrush() -, m_backgroundBrush(::CreateSolidBrush(RGB(0, 0, 0))) +, m_nVInsideBorder(nVInsideBorder) +, m_nHInsideBorder(nHInsideBorder) , m_selectionState(selstateNoSelection) , m_coordInitial() , m_coordCurrent() -/* -, (m_consoleParams->dwColumns - 1)(0) -, (m_consoleParams->dwRows - 1)(0) -*/ { +#ifndef _USE_AERO Helpers::CreateBitmap(dcConsoleView, rectConsoleView.Width(), rectConsoleView.Height(), m_bmpSelection); m_dcSelection.SelectBitmap(m_bmpSelection); m_dcSelection.SetBkColor(RGB(0, 0, 0)); +#endif //!_USE_AERO } SelectionHandler::~SelectionHandler() @@ -60,19 +65,68 @@ SelectionHandler::~SelectionHandler() ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// +void SelectionHandler::SelectWord(const COORD& coordInit, CharInfo screenBuffer []) +{ + if (m_selectionState > selstateNoSelection) return; + + // stop console scrolling while selecting + m_consoleHandler.StopScrolling(); + + 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); + + m_selectionState = selstateSelectWord; + + UpdateSelection(); +} ////////////////////////////////////////////////////////////////////////////// -void SelectionHandler::StartSelection(const COORD& coordInit, COLORREF crSelectionColor, shared_array screenBuffer) +void SelectionHandler::StartSelection(const COORD& coordInit, CharInfo 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; @@ -82,7 +136,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; @@ -103,7 +157,7 @@ void SelectionHandler::StartSelection(const COORD& coordInit, COLORREF crSelecti ////////////////////////////////////////////////////////////////////////////// -void SelectionHandler::UpdateSelection(const COORD& coordCurrent, shared_array screenBuffer) +void SelectionHandler::UpdateSelection(const COORD& coordCurrent, CharInfo screenBuffer []) { if ((m_selectionState != selstateStartedSelecting) && (m_selectionState != selstateSelecting)) @@ -117,7 +171,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; @@ -142,7 +196,9 @@ void SelectionHandler::UpdateSelection() { if (m_selectionState < selstateStartedSelecting) return; +#ifndef _USE_AERO m_dcSelection.FillRect(&m_rectConsoleView, m_backgroundBrush); +#endif //!_USE_AERO COORD coordStart; COORD coordEnd; @@ -159,6 +215,7 @@ void SelectionHandler::UpdateSelection() if (m_selectionState < selstateSelecting) m_selectionState = selstateSelecting; +#ifndef _USE_AERO /* TRACE(L"Member coord: %ix%i - %ix%i\n", m_coordInitial.X, m_coordInitial.Y, m_coordCurrent.X, m_coordCurrent.Y); TRACE(L"Sel coord: %ix%i - %ix%i\n", coordStart.X, coordStart.Y, coordEnd.X, coordEnd.Y); @@ -207,6 +264,23 @@ void SelectionHandler::UpdateSelection() // TRACE(L"fill rect: (%ix%i) - (%ix%i)\n", fillRect.left, fillRect.top, fillRect.right, fillRect.bottom); m_dcSelection.FillRect(&fillRect, m_paintBrush); } +#endif //!_USE_AREO +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void SelectionHandler::SelectAll(void) +{ + m_coordInitial.X = 0; + m_coordInitial.Y = 0; + m_coordCurrent.X = m_consoleInfo->csbi.dwSize.X - 1; + m_coordCurrent.Y = m_consoleInfo->csbi.dwSize.Y - 1; + m_selectionState = selstateSelected; + + UpdateSelection(); } ////////////////////////////////////////////////////////////////////////////// @@ -264,6 +338,15 @@ 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_s( + m_consoleCopyInfo->szFontName, sizeof(m_consoleCopyInfo->szFontName), + _TRUNCATE, + "%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(); } @@ -297,7 +380,9 @@ void SelectionHandler::ClearSelection() m_selectionState = selstateNoSelection; +#ifndef _USE_AERO m_dcSelection.FillRect(&m_rectConsoleView, m_backgroundBrush); +#endif //!_USE_AERO m_consoleHandler.ResumeScrolling(); } @@ -306,6 +391,93 @@ void SelectionHandler::ClearSelection() ////////////////////////////////////////////////////////////////////////////// +#ifdef _USE_AERO + +void SelectionHandler::Draw(CDC& offscreenDC) +{ + if (m_selectionState == selstateNoSelection) return; + + COORD coordStart; + COORD coordEnd; + SHORT maxX = (m_consoleParams->dwBufferColumns > 0) ? + static_cast(m_consoleParams->dwBufferColumns - 1) : + static_cast(m_consoleParams->dwColumns - 1); + + GetSelectionCoordinates(coordStart, coordEnd); + + SMALL_RECT& srWindow = m_consoleInfo->csbi.srWindow; + + if( coordEnd.Y < srWindow.Top || + coordStart.Y > srWindow.Bottom ) return; + + INT nXStart = (static_cast(coordStart.X) - static_cast(srWindow.Left)) * m_nCharWidth + m_nVInsideBorder; + INT nYStart = (static_cast(coordStart.Y) - static_cast(srWindow.Top) ) * m_nCharHeight + m_nHInsideBorder; + INT nXEnd = (static_cast( coordEnd.X) - static_cast(srWindow.Left)) * m_nCharWidth + m_nVInsideBorder; + INT nYEnd = (static_cast( coordEnd.Y) - static_cast(srWindow.Top) ) * m_nCharHeight + m_nHInsideBorder; + INT nXmin = (static_cast(0) - static_cast(srWindow.Left)) * m_nCharWidth + m_nVInsideBorder; + INT nXmax = (static_cast(maxX) - static_cast(srWindow.Left)) * m_nCharWidth + m_nVInsideBorder; + + Gdiplus::Graphics gr(offscreenDC); + + Gdiplus::Color selectionColor; + selectionColor.SetFromCOLORREF(g_settingsHandler->GetAppearanceSettings().stylesSettings.crSelectionColor); + Gdiplus::Pen pen (selectionColor); + Gdiplus::SolidBrush brush(Gdiplus::Color(64, selectionColor.GetR(), selectionColor.GetG(), selectionColor.GetB())); + Gdiplus::GraphicsPath gp; + + if( nYStart == nYEnd ) + { + Gdiplus::Rect rect( + nXStart, + nYStart, + (nXEnd - nXStart) + m_nCharWidth, + m_nCharHeight); + gp.AddRectangle(rect); + } + else + { + /* + 2_________3 + 0______| | + | 1 5___| + |____________| 4 + 7 6 + */ + + Gdiplus::Point points[8]; + + points[0].X = nXmin; + points[0].Y = nYStart + m_nCharHeight; + + points[1].X = nXStart; + points[1].Y = points[0].Y; + + points[2].X = points[1].X; + points[2].Y = nYStart; + + points[3].X = nXmax + m_nCharWidth; + points[3].Y = points[2].Y; + + points[4].X = points[3].X; + points[4].Y = nYEnd; + + points[5].X = nXEnd + m_nCharWidth; + points[5].Y = points[4].Y; + + points[6].X = points[5].X; + points[6].Y = nYEnd + m_nCharHeight; + + points[7].X = points[0].X; + points[7].Y = points[6].Y; + + gp.AddPolygon(points, 8); + } + + gr.FillPath(&brush, &gp); + gr.DrawPath(&pen, &gp); +} + +#else //_USE_AERO void SelectionHandler::BitBlt(CDC& offscreenDC) { @@ -333,6 +505,8 @@ void SelectionHandler::BitBlt(CDC& offscreenDC) SRCINVERT); } +#endif //_USE_AERO + ////////////////////////////////////////////////////////////////////////////// @@ -370,36 +544,52 @@ void SelectionHandler::GetSelectionCoordinates(COORD& coordStart, COORD& coordEn } } +DWORD SelectionHandler::GetSelectionSize(void) +{ + if (m_selectionState < selstateSelecting) return 0; + + COORD coordStart; + COORD coordEnd; + + GetSelectionCoordinates(coordStart, coordEnd); + + DWORD dwColumns = m_consoleParams->dwBufferColumns > 0 ? m_consoleParams->dwBufferColumns : m_consoleParams->dwColumns; + return dwColumns * (coordEnd.Y - coordStart.Y) + (coordEnd.X - coordStart.X) + 1; +} + ////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// +#ifndef _USE_AERO + 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); - 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; } +#endif //!_USE_AERO + ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index 5b135f0a..d0ca4481 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -19,60 +19,78 @@ class SelectionHandler selstateNoSelection = 0x00, selstateStartedSelecting= 0x01, selstateSelecting = 0x02, - selstateSelected = 0x03 + selstateSelected = 0x03, + selstateSelectWord = 0x04, }; public: SelectionHandler( const CWindow& consoleView, +#ifndef _USE_AERO const CDC& dcConsoleView, const CRect& rectConsoleView, +#endif //!_USE_AERO ConsoleHandler& consoleHandler, SharedMemory& consoleParams, - SharedMemory& consoleInfo, + SharedMemory& consoleInfo, SharedMemory& consoleCopyInfo, int nCharWidth, - int nCharHeight); + int nCharHeight, + int nVInsideBorder, + int nHInsideBorder); ~SelectionHandler(); public: - void StartSelection(const COORD& coordInit, COLORREF crSelectionColor, shared_array screenBuffer); - void UpdateSelection(const COORD& coordCurrent, shared_array screenBuffer); + void StartSelection(const COORD& coordInit, CharInfo screenBuffer []); + void SelectWord(const COORD& coordInit, CharInfo screenBuffer []); + void UpdateSelection(const COORD& coordCurrent, CharInfo screenBuffer []); void UpdateSelection(); bool CopySelection(const COORD& coordCurrent); void CopySelection(); void EndSelection(); void ClearSelection(); + void SelectAll(); inline SelectionState GetState() const; + DWORD GetSelectionSize(void); +#ifdef _USE_AERO + void Draw(CDC& offscreenDC); +#else //_USE_AERO void BitBlt(CDC& offscreenDC); + private: + void GetFillRect(const COORD& coordStart, const COORD& coordEnd, CRect& fillRect); +#endif //_USE_AERO + private: void GetSelectionCoordinates(COORD& coordStart, COORD& coordEnd); - void GetFillRect(const COORD& coordStart, const COORD& coordEnd, CRect& fillRect); private: CWindow m_consoleView; +#ifndef _USE_AERO CDC m_dcSelection; CBitmap m_bmpSelection; CRect m_rectConsoleView; - ConsoleHandler& m_consoleHandler; - SharedMemory& m_consoleParams; - SharedMemory& m_consoleInfo; - SharedMemory& m_consoleCopyInfo; - int m_nCharWidth; - int m_nCharHeight; - CBrush m_paintBrush; CBrush m_backgroundBrush; +#endif //!_USE_AERO + + ConsoleHandler& m_consoleHandler; + SharedMemory& m_consoleParams; + SharedMemory& m_consoleInfo; + SharedMemory& m_consoleCopyInfo; + int m_nCharWidth; + int m_nCharHeight; + int m_nVInsideBorder; + int m_nHInsideBorder; SelectionState m_selectionState; diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index d90600a9..725d9ad3 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -8,7 +8,7 @@ using namespace boost::algorithm; ////////////////////////////////////////////////////////////////////////////// -extern shared_ptr g_imageHandler; +extern std::shared_ptr g_imageHandler; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -47,6 +47,7 @@ ConsoleSettings::ConsoleSettings() , dwBufferColumns(80) , bStartHidden(false) , bSaveSize(false) +, backgroundTextOpacity(255) { defaultConsoleColors[0] = 0x000000; defaultConsoleColors[1] = 0x800000; @@ -89,12 +90,13 @@ bool ConsoleSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"buffer_columns"), dwBufferColumns, 0); XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"start_hidden"), bStartHidden, false); XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"save_size"), bSaveSize, false); + XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"background_text_opacity"), backgroundTextOpacity, 255); for (DWORD i = 0; i < 16; ++i) { CComPtr pFontColorElement; - if (FAILED(XmlHelper::GetDomElement(pConsoleElement, CComBSTR(str(wformat(L"colors/color[%1%]") % i).c_str()), pFontColorElement))) continue; + if (FAILED(XmlHelper::GetDomElement(pConsoleElement, CComBSTR(boost::str(boost::wformat(L"colors/color[%1%]") % i).c_str()), pFontColorElement))) continue; DWORD id; @@ -126,12 +128,13 @@ bool ConsoleSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pConsoleElement, CComBSTR(L"buffer_columns"), dwBufferColumns); XmlHelper::SetAttribute(pConsoleElement, CComBSTR(L"start_hidden"), bStartHidden); XmlHelper::SetAttribute(pConsoleElement, CComBSTR(L"save_size"), bSaveSize); + XmlHelper::SetAttribute(pConsoleElement, CComBSTR(L"background_text_opacity"), backgroundTextOpacity); for (DWORD i = 0; i < 16; ++i) { CComPtr pFontColorElement; - if (FAILED(XmlHelper::GetDomElement(pConsoleElement, CComBSTR(str(wformat(L"colors/color[%1%]") % i).c_str()), pFontColorElement))) continue; + if (FAILED(XmlHelper::GetDomElement(pConsoleElement, CComBSTR(boost::str(boost::wformat(L"colors/color[%1%]") % i).c_str()), pFontColorElement))) continue; XmlHelper::SetAttribute(pFontColorElement, CComBSTR(L"id"), i); XmlHelper::SetRGBAttribute(pFontColorElement, consoleColors[i]); @@ -161,6 +164,8 @@ ConsoleSettings& ConsoleSettings::operator=(const ConsoleSettings& other) ::CopyMemory(consoleColors, other.consoleColors, sizeof(COLORREF)*16); + backgroundTextOpacity = other.backgroundTextOpacity; + return *this; } @@ -282,6 +287,7 @@ WindowSettings::WindowSettings() , bShowCommandInTabs(true) , bUseTabTitles(false) , dwTrimTabTitles(0) +, dwTrimTabTitlesRight(0) { } @@ -304,6 +310,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 +334,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 +354,7 @@ WindowSettings& WindowSettings::operator=(const WindowSettings& other) bShowCommandInTabs = other.bShowCommandInTabs; bUseTabTitles = other.bUseTabTitles; dwTrimTabTitles = other.dwTrimTabTitles; + dwTrimTabTitlesRight= other.dwTrimTabTitlesRight; return *this; } @@ -366,6 +375,7 @@ ControlsSettings::ControlsSettings() , bShowStatusbar(true) , bShowTabs(true) , bHideSingleTab(false) +, bTabsOnBottom(false) , bShowScrollbars(true) , bFlatScrollbars(false) { @@ -387,6 +397,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_on_bottom"), bTabsOnBottom, false); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_scrollbars"), bShowScrollbars, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"flat_scrollbars"), bFlatScrollbars, false); @@ -409,6 +420,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_on_bottom"), bTabsOnBottom); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_scrollbars"), bShowScrollbars); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"flat_scrollbars"), bFlatScrollbars); @@ -427,6 +439,7 @@ ControlsSettings& ControlsSettings::operator=(const ControlsSettings& other) bShowStatusbar = other.bShowStatusbar; bShowTabs = other.bShowTabs; bHideSingleTab = other.bHideSingleTab; + bTabsOnBottom = other.bTabsOnBottom; bShowScrollbars = other.bShowScrollbars; bFlatScrollbars = other.bFlatScrollbars; @@ -450,6 +463,8 @@ StylesSettings::StylesSettings() , bBorder(true) , dwInsideBorder(2) , bTrayIcon(false) +, bQuake(false) +, bJumplist(false) , crSelectionColor(RGB(255, 255, 255)) { } @@ -471,6 +486,8 @@ 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); + XmlHelper::GetAttribute(pStylesElement, CComBSTR(L"jumplist"), bJumplist, false); CComPtr pSelColorElement; @@ -498,6 +515,8 @@ 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); + XmlHelper::SetAttribute(pStylesElement, CComBSTR(L"jumplist"), bJumplist); CComPtr pSelColorElement; @@ -521,6 +540,8 @@ StylesSettings& StylesSettings::operator=(const StylesSettings& other) bBorder = other.bBorder; dwInsideBorder = other.dwInsideBorder; bTrayIcon = other.bTrayIcon; + bQuake = other.bQuake; + bJumplist = other.bJumplist; crSelectionColor= other.crSelectionColor; return *this; @@ -613,6 +634,8 @@ PositionSettings& PositionSettings::operator=(const PositionSettings& other) ////////////////////////////////////////////////////////////////////////////// +BYTE TransparencySettings::minAlpha = 5; + ////////////////////////////////////////////////////////////////////////////// TransparencySettings::TransparencySettings() @@ -639,6 +662,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; } @@ -773,6 +799,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); @@ -795,6 +822,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)); @@ -811,6 +839,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; @@ -948,77 +977,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() @@ -1035,7 +993,6 @@ bool BehaviorSettings::Load(const CComPtr& pSettingsRoot) copyPasteSettings.Load(pSettingsRoot); scrollSettings.Load(pSettingsRoot); tabHighlightSettings.Load(pSettingsRoot); -// animateSettings.Load(pSettingsRoot); return true; } @@ -1049,7 +1006,6 @@ bool BehaviorSettings::Save(const CComPtr& pSettingsRoot) copyPasteSettings.Save(pSettingsRoot); scrollSettings.Save(pSettingsRoot); tabHighlightSettings.Save(pSettingsRoot); -// animateSettings.Save(pSettingsRoot); return true; } @@ -1063,7 +1019,6 @@ BehaviorSettings& BehaviorSettings::operator=(const BehaviorSettings& other) copyPasteSettings = other.copyPasteSettings; scrollSettings = other.scrollSettings; tabHighlightSettings= other.tabHighlightSettings; -// animateSettings = other.animateSettings; return *this; } @@ -1081,57 +1036,70 @@ BehaviorSettings& BehaviorSettings::operator=(const BehaviorSettings& other) HotKeys::HotKeys() : bUseScrollLock(false) { - commands.push_back(shared_ptr(new CommandData(L"settings", ID_EDIT_SETTINGS, L"Settings dialog"))); - commands.push_back(shared_ptr(new CommandData(L"help", ID_HELP, L"Help"))); - - commands.push_back(shared_ptr(new CommandData(L"exit", ID_APP_EXIT, L"Exit Console"))); - - commands.push_back(shared_ptr(new CommandData(L"newtab1", ID_NEW_TAB_1, L"New Tab 1"))); - commands.push_back(shared_ptr(new CommandData(L"newtab2", ID_NEW_TAB_1 + 1, L"New Tab 2"))); - commands.push_back(shared_ptr(new CommandData(L"newtab3", ID_NEW_TAB_1 + 2, L"New Tab 3"))); - commands.push_back(shared_ptr(new CommandData(L"newtab4", ID_NEW_TAB_1 + 3, L"New Tab 4"))); - commands.push_back(shared_ptr(new CommandData(L"newtab5", ID_NEW_TAB_1 + 4, L"New Tab 5"))); - commands.push_back(shared_ptr(new CommandData(L"newtab6", ID_NEW_TAB_1 + 5, L"New Tab 6"))); - commands.push_back(shared_ptr(new CommandData(L"newtab7", ID_NEW_TAB_1 + 6, L"New Tab 7"))); - commands.push_back(shared_ptr(new CommandData(L"newtab8", ID_NEW_TAB_1 + 7, L"New Tab 8"))); - commands.push_back(shared_ptr(new CommandData(L"newtab9", ID_NEW_TAB_1 + 8, L"New Tab 9"))); - commands.push_back(shared_ptr(new CommandData(L"newtab10", ID_NEW_TAB_1 + 9, L"New Tab 10"))); - - commands.push_back(shared_ptr(new CommandData(L"switchtab1", ID_SWITCH_TAB_1, L"Switch to tab 1"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab2", ID_SWITCH_TAB_1 + 1,L"Switch to tab 2"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab3", ID_SWITCH_TAB_1 + 2,L"Switch to tab 3"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab4", ID_SWITCH_TAB_1 + 3,L"Switch to tab 4"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab5", ID_SWITCH_TAB_1 + 4,L"Switch to tab 5"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab6", ID_SWITCH_TAB_1 + 5,L"Switch to tab 6"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab7", ID_SWITCH_TAB_1 + 6,L"Switch to tab 7"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab8", ID_SWITCH_TAB_1 + 7,L"Switch to tab 8"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab9", ID_SWITCH_TAB_1 + 8,L"Switch to tab 9"))); - commands.push_back(shared_ptr(new CommandData(L"switchtab10", ID_SWITCH_TAB_1 + 9,L"Switch to tab 10"))); - - commands.push_back(shared_ptr(new CommandData(L"nexttab", ID_NEXT_TAB, L"Next tab"))); - commands.push_back(shared_ptr(new CommandData(L"prevtab", ID_PREV_TAB, L"Previous tab"))); - - 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"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"))); - commands.push_back(shared_ptr(new CommandData(L"stopscroll", ID_EDIT_STOP_SCROLLING, L"Stop scrolling"))); - - commands.push_back(shared_ptr(new CommandData(L"scrollrowup", ID_SCROLL_UP, L"Scroll buffer row up"))); - commands.push_back(shared_ptr(new CommandData(L"scrollrowdown", ID_SCROLL_DOWN, L"Scroll buffer row down"))); - commands.push_back(shared_ptr(new CommandData(L"scrollpageup", ID_SCROLL_PAGE_UP, L"Scroll buffer page up"))); - commands.push_back(shared_ptr(new CommandData(L"scrollpagedown", ID_SCROLL_PAGE_DOWN, L"Scroll buffer page down"))); - commands.push_back(shared_ptr(new CommandData(L"scrollcolleft", ID_SCROLL_LEFT, L"Scroll buffer column left"))); - commands.push_back(shared_ptr(new CommandData(L"scrollcolright", ID_SCROLL_RIGHT, L"Scroll buffer column right"))); - commands.push_back(shared_ptr(new CommandData(L"scrollpageleft", ID_SCROLL_PAGE_LEFT, L"Scroll buffer page left"))); - commands.push_back(shared_ptr(new CommandData(L"scrollpageright", ID_SCROLL_PAGE_RIGHT, L"Scroll buffer page right"))); - - commands.push_back(shared_ptr(new CommandData(L"dumpbuffer", IDC_DUMP_BUFFER, L"Dump screen buffer"))); + commands.push_back(std::shared_ptr(new CommandData(L"settings", ID_EDIT_SETTINGS, L"Settings dialog"))); + commands.push_back(std::shared_ptr(new CommandData(L"help", ID_HELP, L"Help"))); + + commands.push_back(std::shared_ptr(new CommandData(L"exit", ID_APP_EXIT, L"Exit Console"))); + + commands.push_back(std::shared_ptr(new CommandData(L"newtab1", ID_NEW_TAB_1, L"New Tab 1"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab2", ID_NEW_TAB_1 + 1, L"New Tab 2"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab3", ID_NEW_TAB_1 + 2, L"New Tab 3"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab4", ID_NEW_TAB_1 + 3, L"New Tab 4"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab5", ID_NEW_TAB_1 + 4, L"New Tab 5"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab6", ID_NEW_TAB_1 + 5, L"New Tab 6"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab7", ID_NEW_TAB_1 + 6, L"New Tab 7"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab8", ID_NEW_TAB_1 + 7, L"New Tab 8"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab9", ID_NEW_TAB_1 + 8, L"New Tab 9"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab10", ID_NEW_TAB_1 + 9, L"New Tab 10"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab11", ID_NEW_TAB_1 + 10, L"New Tab 11"))); + commands.push_back(std::shared_ptr(new CommandData(L"newtab12", ID_NEW_TAB_1 + 11, L"New Tab 12"))); + + commands.push_back(std::shared_ptr(new CommandData(L"switchtab1", ID_SWITCH_TAB_1, L"Switch to tab 1"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab2", ID_SWITCH_TAB_1 + 1,L"Switch to tab 2"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab3", ID_SWITCH_TAB_1 + 2,L"Switch to tab 3"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab4", ID_SWITCH_TAB_1 + 3,L"Switch to tab 4"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab5", ID_SWITCH_TAB_1 + 4,L"Switch to tab 5"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab6", ID_SWITCH_TAB_1 + 5,L"Switch to tab 6"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab7", ID_SWITCH_TAB_1 + 6,L"Switch to tab 7"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab8", ID_SWITCH_TAB_1 + 7,L"Switch to tab 8"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab9", ID_SWITCH_TAB_1 + 8,L"Switch to tab 9"))); + commands.push_back(std::shared_ptr(new CommandData(L"switchtab10", ID_SWITCH_TAB_1 + 9,L"Switch to tab 10"))); + + commands.push_back(std::shared_ptr(new CommandData(L"nexttab", ID_NEXT_TAB, L"Next tab"))); + commands.push_back(std::shared_ptr(new CommandData(L"prevtab", ID_PREV_TAB, L"Previous tab"))); + + commands.push_back(std::shared_ptr(new CommandData(L"closetab", ID_FILE_CLOSE_TAB, L"Close tab"))); + commands.push_back(std::shared_ptr(new CommandData(L"renametab", ID_EDIT_RENAME_TAB, L"Rename tab"))); + + commands.push_back(std::shared_ptr(new CommandData(L"nextview", ID_NEXT_VIEW, L"Next view"))); + commands.push_back(std::shared_ptr(new CommandData(L"prevview", ID_PREV_VIEW, L"Previous view"))); + commands.push_back(std::shared_ptr(new CommandData(L"closeview", ID_CLOSE_VIEW, L"Close view"))); + commands.push_back(std::shared_ptr(new CommandData(L"splithoriz", ID_SPLIT_HORIZ, L"Split horizontally"))); + commands.push_back(std::shared_ptr(new CommandData(L"splitvert", ID_SPLIT_VERT, L"Split vertically"))); + commands.push_back(std::shared_ptr(new CommandData(L"groupall", ID_GROUP_ALL, L"Group all"))); + commands.push_back(std::shared_ptr(new CommandData(L"ungroupall", ID_UNGROUP_ALL, L"Ungroup all"))); + commands.push_back(std::shared_ptr(new CommandData(L"grouptab", ID_GROUP_TAB, L"Group tab"))); + commands.push_back(std::shared_ptr(new CommandData(L"ungrouptab", ID_UNGROUP_TAB, L"Ungroup tab"))); + + commands.push_back(std::shared_ptr(new CommandData(L"copy", ID_EDIT_COPY, L"Copy selection"))); + commands.push_back(std::shared_ptr(new CommandData(L"selectall", ID_EDIT_SELECT_ALL, L"Select all"))); + commands.push_back(std::shared_ptr(new CommandData(L"clear_selection",ID_EDIT_CLEAR_SELECTION, L"Clear selection"))); + commands.push_back(std::shared_ptr(new CommandData(L"paste", ID_EDIT_PASTE, L"Paste"))); + commands.push_back(std::shared_ptr(new CommandData(L"stopscroll", ID_EDIT_STOP_SCROLLING, L"Stop scrolling"))); + + commands.push_back(std::shared_ptr(new CommandData(L"scrollrowup", ID_SCROLL_UP, L"Scroll buffer row up"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollrowdown", ID_SCROLL_DOWN, L"Scroll buffer row down"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollpageup", ID_SCROLL_PAGE_UP, L"Scroll buffer page up"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollpagedown", ID_SCROLL_PAGE_DOWN, L"Scroll buffer page down"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollcolleft", ID_SCROLL_LEFT, L"Scroll buffer column left"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollcolright", ID_SCROLL_RIGHT, L"Scroll buffer column right"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollpageleft", ID_SCROLL_PAGE_LEFT, L"Scroll buffer page left"))); + commands.push_back(std::shared_ptr(new CommandData(L"scrollpageright", ID_SCROLL_PAGE_RIGHT, L"Scroll buffer page right"))); + + commands.push_back(std::shared_ptr(new CommandData(L"dumpbuffer", IDC_DUMP_BUFFER, L"Dump screen buffer"))); // global commands - commands.push_back(shared_ptr(new CommandData(L"activate", IDC_GLOBAL_ACTIVATE, L"Activate Console (global)", true))); + commands.push_back(std::shared_ptr(new CommandData(L"activate", IDC_GLOBAL_ACTIVATE, L"Activate Console (global)", true))); } ////////////////////////////////////////////////////////////////////////////// @@ -1299,11 +1267,11 @@ HotKeys& HotKeys::operator=(const HotKeys& other) MouseSettings::MouseSettings() : commands() { - commands.push_back(shared_ptr(new CommandData(cmdCopy, L"copy", L"Copy/clear selection"))); - commands.push_back(shared_ptr(new CommandData(cmdSelect, L"select", L"Select text"))); - commands.push_back(shared_ptr(new CommandData(cmdPaste, L"paste", L"Paste text"))); - commands.push_back(shared_ptr(new CommandData(cmdDrag, L"drag", L"Drag window"))); - commands.push_back(shared_ptr(new CommandData(cmdMenu, L"menu", L"Context menu"))); + commands.push_back(std::shared_ptr(new CommandData(cmdCopy, L"copy", L"Copy/clear selection"))); + commands.push_back(std::shared_ptr(new CommandData(cmdSelect, L"select", L"Select text"))); + commands.push_back(std::shared_ptr(new CommandData(cmdPaste, L"paste", L"Paste text"))); + commands.push_back(std::shared_ptr(new CommandData(cmdDrag, L"drag", L"Drag window"))); + commands.push_back(std::shared_ptr(new CommandData(cmdMenu, L"menu", L"Context menu"))); } ////////////////////////////////////////////////////////////////////////////// @@ -1485,13 +1453,14 @@ bool TabSettings::Load(const CComPtr& pSettingsRoot) pTabNodes->get_item(i, &pTabNode); if (FAILED(pTabNode.QueryInterface(&pTabElement))) continue; - shared_ptr tabData(new TabData(strDefaultShell, strDefaultInitialDir)); + std::shared_ptr tabData(new TabData(strDefaultShell, strDefaultInitialDir)); CComPtr pConsoleElement; CComPtr pCursorElement; CComPtr pBackgroundElement; 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); @@ -1499,6 +1468,9 @@ 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""); + XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"net_only"), tabData->bNetOnly, false); } if (SUCCEEDED(XmlHelper::GetDomElement(pTabElement, CComBSTR(L"cursor"), pCursorElement))) @@ -1603,6 +1575,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; @@ -1611,6 +1585,9 @@ 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); + XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"net_only"), (*itTab)->bNetOnly); SettingsBase::AddTextNode(pSettingsDoc, pNewTabElement, CComBSTR(L"\n\t\t\t")); pNewTabElement->appendChild(pNewConsoleElement, &pNewConsoleOut); @@ -1786,6 +1763,17 @@ bool SettingsHandler::LoadSettings(const wstring& strSettingsFileName) m_strSettingsPath = Helpers::GetModulePath(NULL); m_settingsDirType = dirTypeExe; + hr = XmlHelper::OpenXmlDocument( + GetSettingsFileName(), + m_pSettingsDocument, + m_pSettingsRoot); + } + + if (FAILED(hr)) + { + m_strSettingsPath = L"res://" + Helpers::GetModuleFileName(NULL) + L"/"; + m_settingsDirType = dirTypeExe; + hr = XmlHelper::OpenXmlDocument( GetSettingsFileName(), m_pSettingsDocument, diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 52fb495c..39e21b76 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -51,6 +51,7 @@ struct ConsoleSettings : public SettingsBase COLORREF defaultConsoleColors[16]; COLORREF consoleColors[16]; + BYTE backgroundTextOpacity; }; ////////////////////////////////////////////////////////////////////////////// @@ -115,6 +116,7 @@ struct WindowSettings : public SettingsBase bool bShowCommandInTabs; bool bUseTabTitles; DWORD dwTrimTabTitles; + DWORD dwTrimTabTitlesRight; }; ////////////////////////////////////////////////////////////////////////////// @@ -136,6 +138,7 @@ struct ControlsSettings bool bShowStatusbar; bool bShowTabs; bool bHideSingleTab; + bool bTabsOnBottom; bool bShowScrollbars; bool bFlatScrollbars; }; @@ -160,6 +163,8 @@ struct StylesSettings : public SettingsBase bool bBorder; DWORD dwInsideBorder; bool bTrayIcon; + bool bQuake; + bool bJumplist; COLORREF crSelectionColor; }; @@ -221,7 +226,8 @@ enum TransparencyType { transNone = 0, transAlpha = 1, - transColorKey = 2 + transColorKey = 2, + transGlass = 3 }; ////////////////////////////////////////////////////////////////////////////// @@ -242,6 +248,8 @@ struct TransparencySettings : public SettingsBase BYTE byActiveAlpha; BYTE byInactiveAlpha; COLORREF crColorKey; + + static BYTE minAlpha; }; ////////////////////////////////////////////////////////////////////////////// @@ -282,6 +290,7 @@ struct CopyPasteSettings : public SettingsBase bool bCopyOnSelect; bool bClearOnCopy; + bool bSensitiveCopy; bool bNoWrap; bool bTrimSpaces; @@ -326,51 +335,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 @@ -385,7 +349,6 @@ struct BehaviorSettings : public SettingsBase CopyPasteSettings copyPasteSettings; ScrollSettings scrollSettings; TabHighlightSettings tabHighlightSettings; -// AnimateSettings animateSettings; }; ////////////////////////////////////////////////////////////////////////////// @@ -414,6 +377,49 @@ struct HotKeys : public SettingsBase ::ZeroMemory(&accelHotkey, sizeof(ACCEL)); } + std::wstring GetHotKeyName(void) + { + std::wstring strHotKeyName; + + if( this->accelHotkey.fVirt || this->accelHotkey.key ) + { + LONG lScanCode; + wchar_t szKeyName[32]; + + if (this->accelHotkey.fVirt & FCONTROL) + { + lScanCode = ::MapVirtualKey(VK_CONTROL, 0) << 16; + if( ::GetKeyNameText(lScanCode, szKeyName, ARRAYSIZE(szKeyName)) ) + strHotKeyName += szKeyName; + strHotKeyName += L"+"; + } + + if (this->accelHotkey.fVirt & FSHIFT) + { + lScanCode = ::MapVirtualKey(VK_SHIFT, 0) << 16; + if( ::GetKeyNameText(lScanCode, szKeyName, ARRAYSIZE(szKeyName)) ) + strHotKeyName += szKeyName; + strHotKeyName += L"+"; + } + + if (this->accelHotkey.fVirt & FALT) + { + lScanCode = ::MapVirtualKey(VK_MENU, 0) << 16; + if( ::GetKeyNameText(lScanCode, szKeyName, ARRAYSIZE(szKeyName)) ) + strHotKeyName += szKeyName; + strHotKeyName += L"+"; + } + + lScanCode = ::MapVirtualKey(this->accelHotkey.key, 0) << 16; + if (this->bExtended) lScanCode |= 0x01000000L; + + if( ::GetKeyNameText(lScanCode, szKeyName, ARRAYSIZE(szKeyName)) ) + strHotKeyName += szKeyName; + } + + return strHotKeyName; + } + wstring strCommand; WORD wCommandID; wstring strDescription; @@ -426,7 +432,7 @@ struct HotKeys : public SettingsBase struct commandID{}; typedef multi_index_container< - shared_ptr, + std::shared_ptr, indexed_by < sequenced<>, @@ -537,7 +543,7 @@ struct MouseSettings : public SettingsBase struct commandName{}; typedef multi_index_container< - shared_ptr, + std::shared_ptr, indexed_by < sequenced<>, @@ -578,12 +584,17 @@ struct TabData TabData(const wstring& shell, const wstring& initialDir) : strTitle(L"Console") , strIcon(L"") + , bUseDefaultIcon(false) , strShell(shell) , strInitialDir(initialDir) + , bRunAsUser(false) + , strUser() + , bNetOnly(false) , dwCursorStyle(0) , crCursorColor(RGB(255, 255, 255)) , backgroundImageType(bktypeNone) , crBackgroundColor(RGB(0, 0, 0)) + , menuBitmap() , imageData() { } @@ -591,9 +602,13 @@ struct TabData // custom shell settings wstring strTitle; wstring strIcon; + bool bUseDefaultIcon; wstring strShell; wstring strInitialDir; + bool bRunAsUser; + wstring strUser; + bool bNetOnly; DWORD dwCursorStyle; COLORREF crCursorColor; @@ -601,6 +616,8 @@ struct TabData BackgroundImageType backgroundImageType; COLORREF crBackgroundColor; + CBitmap menuBitmap; + ImageData imageData; }; @@ -609,7 +626,7 @@ struct TabData ////////////////////////////////////////////////////////////////////////////// -typedef vector > TabDataVector; +typedef vector > TabDataVector; struct TabSettings : public SettingsBase { @@ -659,6 +676,8 @@ class SettingsHandler bool SaveSettings(); wstring GetSettingsFileName() const { return m_strSettingsPath+m_strSettingsFileName; } + wstring GetSettingsPath() const { return m_strSettingsPath; } + wstring GetSettingsTitle() const { return m_strSettingsFileName; } SettingsDirType GetSettingsDirType() const { return m_settingsDirType; } void SetUserDataDir(SettingsDirType settingsDirType); diff --git a/Console/TabView.cpp b/Console/TabView.cpp new file mode 100644 index 00000000..29d5921b --- /dev/null +++ b/Console/TabView.cpp @@ -0,0 +1,620 @@ +#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; + + +////////////////////////////////////////////////////////////////////////////// + +TabView::TabView(MainFrame& mainFrame, std::shared_ptr tabData, const wstring& strCmdLineInitialDir, const wstring& strCmdLineInitialCmd) +:m_mainFrame(mainFrame) +,m_viewsMutex(NULL, FALSE, NULL) +,m_tabData(tabData) +,m_strTitle(tabData->strTitle.c_str()) +,m_bigIcon() +,m_smallIcon() +,m_boolIsGrouped(false) +,m_strCmdLineInitialDir(strCmdLineInitialDir) +,m_strCmdLineInitialCmd(strCmdLineInitialCmd) +{ +} + +TabView::~TabView() +{ +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +BOOL TabView::PreTranslateMessage(MSG* pMsg) +{ + 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; + + /* + std::shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); + 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(m_strCmdLineInitialDir, m_strCmdLineInitialCmd); + if( hwndConsoleView ) + { + result = multisplitClass::OnCreate(uMsg, wParam, lParam, bHandled); + TRACE(L"multisplitClass::OnCreate returns %p\n", result); + if( result == 0 ) + { + multisplitClass::tree.window = hwndConsoleView; + CRect rect; + m_views.begin()->second->GetRect(rect); + multisplitClass::RectSet(rect, true); + } + } + + 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 && m_mainFrame.m_bOnCreateDone) + { + TRACE(L"TabView::OnSize -> multisplitClass::RectSet\n"); + multisplitClass::RectSet(); // to ClientRect + } + + bHandled = FALSE; + return 1; +} + +HWND TabView::CreateNewConsole(const wstring& strCmdLineInitialDir /*= wstring(L"")*/, const wstring& strCmdLineInitialCmd /*= wstring(L"")*/) +{ + 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 + std::shared_ptr consoleView(new ConsoleView(m_mainFrame, m_hWnd, m_tabData, m_strTitle, dwRows, dwColumns, strCmdLineInitialDir, strCmdLineInitialCmd)); + consoleView->Group(this->IsGrouped()); + UserCredentials userCredentials; + + if (m_tabData->bRunAsUser) + { + userCredentials.netOnly = m_tabData->bNetOnly; +#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)); + +#ifdef _USE_AERO + m_mainFrame.m_taskBarList.AddTab(consoleView.get(), m_mainFrame.m_hWnd); +#endif + + return hwndConsoleView; +} + +std::shared_ptr TabView::GetActiveConsole(const TCHAR* /*szFrom*/) +{ + std::shared_ptr result; + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + MutexLock viewMapLock(m_viewsMutex); + ConsoleViewMap::iterator iter = m_views.find(multisplitClass::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 multisplitClass::defaultFocusPane = %p\n", multisplitClass::defaultFocusPane); + } + //TRACE(L"TabView::GetActiveConsole called by %s returns %p\n", szFrom, 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::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); + if( bAppActive ) + { + if( this->m_boolIsGrouped ) + { + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(true); + } + } + else + { + std::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 + { + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(false); + } + } +} + +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(as, clientRect, dwResizeWindowEdge); + } + this->GetRect(clientRect); +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void TabView::SplitHorizontally() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + HWND hwndConsoleView = CreateNewConsole(); + if( hwndConsoleView ) + { + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->split( + hwndConsoleView, + CMultiSplitPane::HORIZONTAL)); + + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); + } + } +} + +void TabView::SplitVertically() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + HWND hwndConsoleView = CreateNewConsole(); + if( hwndConsoleView ) + { + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->split( + hwndConsoleView, + CMultiSplitPane::VERTICAL)); + + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); + } + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +bool TabView::CloseView(HWND hwnd /*= 0*/) +{ + if( hwnd == 0 ) + { + if( multisplitClass::defaultFocusPane ) + hwnd = multisplitClass::defaultFocusPane->window; + } + + if( hwnd ) + { + MutexLock viewMapLock(m_viewsMutex); + ConsoleViewMap::iterator iter = m_views.find(hwnd); + if( iter != m_views.end() ) + { + 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 ) + m_mainFrame.CloseTab(this->m_hWnd); + else + { + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); + } + + return true; + } + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +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::SetActiveConsole(HWND hwnd) +{ + MutexLock viewMapLock(m_viewsMutex); + auto it = m_views.find(hwnd); + if( it != m_views.end() ) + multisplitClass::SetDefaultFocusPane(multisplitClass::tree.get(hwnd)); +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void TabView::OnSplitBarMove(HWND /*hwndPane0*/, HWND /*hwndPane1*/, bool /*boolEnd*/) +{ + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, 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::SendTextToConsole(const wchar_t* pszText) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SendTextToConsole(pszText); + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +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; + SetAppActiveStatus(true); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT TabView::OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled) +{ + int nScrollType = 0; + int nScrollCode = 0; + + switch (wID) + { + case ID_SCROLL_UP : + { + nScrollType = SB_VERT; + nScrollCode = SB_LINEUP; + break; + } + + case ID_SCROLL_LEFT : + { + nScrollType = SB_HORZ; + nScrollCode = SB_LINELEFT; + break; + } + + case ID_SCROLL_DOWN : + { + nScrollType = SB_VERT; + nScrollCode = SB_LINEDOWN; + break; + } + + case ID_SCROLL_RIGHT : + { + nScrollType = SB_HORZ; + nScrollCode = SB_LINERIGHT; + break; + } + + case ID_SCROLL_PAGE_UP : + { + nScrollType = SB_VERT; + nScrollCode = SB_PAGEUP; + break; + } + + case ID_SCROLL_PAGE_LEFT : + { + nScrollType = SB_HORZ; + nScrollCode = SB_PAGELEFT; + break; + } + + case ID_SCROLL_PAGE_DOWN : + { + nScrollType = SB_VERT; + nScrollCode = SB_PAGEDOWN; + break; + } + + case ID_SCROLL_PAGE_RIGHT : + { + nScrollType = SB_HORZ; + nScrollCode = SB_PAGERIGHT; + break; + } + + + default : bHandled = FALSE; return 0; + } + + std::shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); + if( consoleView ) + consoleView->DoScroll(nScrollType, nScrollCode, 0); + + return 0; +} \ No newline at end of file diff --git a/Console/TabView.h b/Console/TabView.h new file mode 100644 index 00000000..c868e781 --- /dev/null +++ b/Console/TabView.h @@ -0,0 +1,108 @@ +#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, std::shared_ptr tabData, const wstring& strCmdLineInitialDir, const wstring& strCmdLineInitialCmd); + ~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) + + COMMAND_RANGE_HANDLER(ID_SCROLL_UP, ID_SCROLL_ALL_RIGHT, OnScrollCommand) + + CHAIN_MSG_MAP (multisplitClass) +/* + { + std::shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); + if( consoleView ) + { + if( consoleView->ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult) ) + return true; + } + } +*/ + 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); + LRESULT OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled); + + virtual void OnPaneChanged(void) + { + SetAppActiveStatus(true); + } + + virtual void OnSplitBarMove(HWND hwndPane0, HWND hwndPane1, bool /*boolEnd*/); + + std::shared_ptr GetActiveConsole(const TCHAR*); + std::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 AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge); + void GetRect(CRect& clientRect); + + void SplitHorizontally(); + void SplitVertically(); + bool CloseView(HWND hwnd = 0); + void NextView(); + void PrevView(); + void SetActiveConsole(HWND hwnd); + + void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); + void PasteToConsoles(); + void SendTextToConsole(const wchar_t* pszText); + + inline bool IsGrouped() const { return m_boolIsGrouped; } + void Group(bool b); + + inline size_t GetViewsCount(void) const { return m_views.size(); } + +private: + HWND CreateNewConsole(const wstring& strCmdLineInitialDir = wstring(L""), const wstring& strCmdLineInitialCmd = wstring(L"")); + +private: + MainFrame& m_mainFrame; + ConsoleViewMap m_views; + Mutex m_viewsMutex; + std::shared_ptr m_tabData; + CString m_strTitle; + CIcon m_bigIcon; + CIcon m_smallIcon; + bool m_boolIsGrouped; + wstring m_strCmdLineInitialDir; + wstring m_strCmdLineInitialCmd; + + // static members +private: + +}; + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/TaskBarList.cpp b/Console/TaskBarList.cpp new file mode 100644 index 00000000..2f284d35 --- /dev/null +++ b/Console/TaskBarList.cpp @@ -0,0 +1,312 @@ +#include "stdafx.h" +#include "TaskBarList.h" + + +TaskBarList::TaskBarList(void) +{ + HRESULT hr = m_taskBarList.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER); + if( hr == S_OK ) + { + // Initializes the taskbar list object. + // This method must be called before any other ITaskbarList methods can be called. + hr = m_taskBarList->HrInit(); + } + m_boolSupported = hr == S_OK; +} + + +TaskBarList::~TaskBarList(void) +{ +} + + +void TaskBarList::AddTab(ConsoleView* pConsoleView, HWND hwndMDI) +{ + if( !m_boolSupported ) + return; + + HWND hwndTabProxy = this->CreateTabProxy(pConsoleView); + ATLASSERT(hwndTabProxy != nullptr); + + this->RegisterTab(hwndTabProxy, hwndMDI); + this->SetTabOrder(hwndTabProxy, nullptr); +} + + +void TaskBarList::RefreshTab(ConsoleView* pConsoleView) +{ + if( !m_boolSupported ) + return; + + this->Call(pConsoleView, [](TaskBarList::TabProxyInfo * ptib) + { + TRACE(L"******** TaskBarList::RefreshTab called in thread %lu\n", ::GetCurrentThreadId()); +#ifdef _DEBUG + HRESULT hr = +#endif + ::DwmInvalidateIconicBitmaps(ptib->hwndProxyTab); + ATLASSERT(hr == S_OK); + }); +} + + +void TaskBarList::UpdateTabTitle(ConsoleView* pConsoleView) +{ + if( !m_boolSupported ) + return; + + this->Call(pConsoleView, [](TaskBarList::TabProxyInfo * ptib) + { + TRACE(L"******** TaskBarList::UpdateTabTitle(%s) called in thread %lu\n", ptib->pConsoleView->GetTitle(), ::GetCurrentThreadId()); + ::SetWindowText(ptib->hwndProxyTab, ptib->pConsoleView->GetTitle()); + }); +} + + +void TaskBarList::RemoveTab(ConsoleView* pConsoleView) +{ + if( !m_boolSupported ) + return; + + this->Call(pConsoleView, [](TaskBarList::TabProxyInfo * ptib) + { + TRACE(L"******** TaskBarList::RemoveTab called in thread %lu\n", ::GetCurrentThreadId()); + ptib->pTaskBarList->UnregisterTab(ptib->hwndProxyTab); + }, + true); +} + + +void TaskBarList::SelectTab(ConsoleView* pConsoleView, HWND hwndMDI) +{ + if( !m_boolSupported ) + return; + + this->Call(pConsoleView, [hwndMDI](TaskBarList::TabProxyInfo * ptib) + { + TRACE(L"******** TaskBarList::SelectTab(%s) called in thread %lu\n", ptib->pConsoleView->GetTitle(), ::GetCurrentThreadId()); + ptib->pTaskBarList->SetTabActive(ptib->hwndProxyTab, hwndMDI); + }); +} + + +HRESULT TaskBarList::RegisterTab(HWND hwndTab, HWND hwndMDI) +{ + ATLASSERT(::IsWindow(hwndTab)); + ATLASSERT(::IsWindow(hwndMDI)); + HRESULT hr = m_taskBarList->RegisterTab(hwndTab, hwndMDI); + ATLASSERT(hr == S_OK); + return hr; +} + + +HRESULT TaskBarList::SetTabActive(HWND hwndTab, HWND hwndMDI) +{ + ATLASSERT(::IsWindow(hwndTab)); + ATLASSERT(::IsWindow(hwndMDI)); + HRESULT hr = m_taskBarList->SetTabActive(hwndTab, hwndMDI, 0); + ATLASSERT(hr == S_OK); + return hr; +} + + +HRESULT TaskBarList::SetTabOrder(HWND hwndTab, HWND hwndInsertBefore) +{ + ATLASSERT(::IsWindow(hwndTab)); + HRESULT hr = m_taskBarList->SetTabOrder(hwndTab, hwndInsertBefore); + ATLASSERT(hr == S_OK); + return hr; +} + + +HRESULT TaskBarList::UnregisterTab(HWND hwndTab) +{ + ATLASSERT(::IsWindow(hwndTab)); + return m_taskBarList->UnregisterTab(hwndTab); +} + + +ATOM TaskBarList::RegisterTabProxyClass(const wchar_t * szClassName, HICON hIconSm) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(wcex); + wcex.style = 0; + wcex.lpfnWndProc = &TaskBarList::TabProxyWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = sizeof(TaskBarList::TabProxyInfo *); + wcex.hInstance = ::GetModuleHandle(nullptr); + wcex.hIcon = nullptr; + wcex.hCursor = ::LoadCursor(nullptr,IDC_ARROW); + wcex.hbrBackground = nullptr; + wcex.lpszMenuName = nullptr; + wcex.lpszClassName = szClassName; + wcex.hIconSm = hIconSm; + + return ::RegisterClassEx(&wcex); +} + + +HWND TaskBarList::CreateTabProxy(ConsoleView* pConsoleView) +{ + /* class name */ + wchar_t szClassName[32]; + static int iCount = 0; + _snwprintf_s( + szClassName, ARRAYSIZE(szClassName), + _TRUNCATE, + L"Console2++TabProxy%ld", + iCount ++); + + /* small icon */ + std::shared_ptr tabData = pConsoleView->GetTabData(); + CIcon tabSmallIcon(Helpers::LoadTabIcon(false, tabData->bUseDefaultIcon, tabData->strIcon, tabData->strShell)); + + ATOM atom = this->RegisterTabProxyClass(szClassName, tabSmallIcon); + + if( atom == 0 ) + return nullptr; + + std::shared_ptr tpi(new TaskBarList::TabProxyInfo(this, pConsoleView, atom, tabSmallIcon.Detach())); + + TRACE(L"TaskBarList::CreateTabProxy ptpi=%p\n", tpi.get()); + + HWND hwndTabProxy = ::CreateWindow( + szClassName, + pConsoleView->GetTitle(), + WS_OVERLAPPEDWINDOW, + 0, 0, + 0, 0, + nullptr, + nullptr, + ::GetModuleHandle(0), + tpi.get()); + + if( hwndTabProxy ) + { + HRESULT hr; + + BOOL bHasIconicBitmap = TRUE; + hr = ::DwmSetWindowAttribute( + hwndTabProxy, + DWMWA_HAS_ICONIC_BITMAP, + &bHasIconicBitmap, + sizeof(bHasIconicBitmap)); + ATLASSERT(hr == S_OK); + + BOOL bForceIconic = TRUE; + hr = ::DwmSetWindowAttribute( + hwndTabProxy, + DWMWA_FORCE_ICONIC_REPRESENTATION, + &bForceIconic, + sizeof(bForceIconic)); + ATLASSERT(hr == S_OK); + + m_listTabProxyInfos.push_back(tpi); + } + + return hwndTabProxy; +} + + +LRESULT CALLBACK TaskBarList::TabProxyWndProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam/*,int iTabId*/) +{ + TaskBarList::TabProxyInfo* ptpi = reinterpret_cast(::GetWindowLongPtr(hwnd, GWLP_USERDATA)); + + HRESULT hr; + + switch(Msg) + { + case WM_CREATE: + ptpi = reinterpret_cast(reinterpret_cast(lParam)->lpCreateParams); + ptpi->hwndProxyTab = hwnd; + ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast(ptpi)); + TRACE(L"TaskBarList::TabProxyWndProc hwnd=%p set ptpi=%p\n", hwnd, ptpi); + break; + + case WM_ACTIVATE: + TRACE(L"******** WM_ACTIVATE called in thread %lu\n", ::GetCurrentThreadId()); + ptpi->pConsoleView->Activate(); + break; + + case WM_SETFOCUS: + TRACE(L"******** WM_SETFOCUS called in thread %lu\n", ::GetCurrentThreadId()); + break; + + case WM_SYSCOMMAND: + TRACE(L"******** WM_SYSCOMMAND called in thread %lu\n", ::GetCurrentThreadId()); + break; + + /* Generate a thumbnail of the current tab. Basic procedure: + 1. Generate a full-scale bitmap of the main window. + 2. Overlay a bitmap of the specified tab onto the main + window bitmap. + 3. Shrink the resulting bitmap down to the correct thumbnail size. + + A thumbnail will be dynamically generated, provided the main window + is not currently minimized (as we won't be able to grap a screenshot + of it). If the main window is minimized, we'll use a cached screenshot + of the tab (taken before the main window was minimized). */ + case WM_DWMSENDICONICTHUMBNAIL: + TRACE(L"******** WM_DWMSENDICONICTHUMBNAIL called in thread %lu\n", ::GetCurrentThreadId()); + { + int nMaxWidth = HIWORD(lParam); + int nMaxHeight = LOWORD(lParam); + + CBitmap bmpThumbnail(ptpi->pConsoleView->GetThumbnail(nMaxWidth,nMaxHeight)); + + hr = ::DwmSetIconicThumbnail(hwnd, bmpThumbnail, 0); + ATLASSERT(hr == S_OK); + + return 0; + } + break; + + case WM_DWMSENDICONICLIVEPREVIEWBITMAP: + TRACE(L"******** WM_DWMSENDICONICLIVEPREVIEWBITMAP called in thread %lu\n", ::GetCurrentThreadId()); + { + POINT ptClient; + HBITMAP bmpLivePreview = ptpi->pConsoleView->GetLivePreview(ptClient); + + hr = ::DwmSetIconicLivePreviewBitmap(hwnd, bmpLivePreview, &ptClient, 0); + ATLASSERT(hr == S_OK); + + return 0; + } + break; + + case WM_CLOSE: + ptpi->pConsoleView->OnConsoleClose(); + return 0; + break; + + case WM_SETTEXT: + case WM_ACTIVATEAPP: + break; + + default: + TRACE(L"@@@@@@ message %LX %lu\n", Msg, Msg); + break; + + } + + return ::DefWindowProc(hwnd, Msg, wParam, lParam); +} + +template +inline bool TaskBarList::Call(T m, const std::function & f, bool boolRemove /*= false*/) +{ + for(auto i = m_listTabProxyInfos.begin(); i != m_listTabProxyInfos.end(); ++i) + { + TaskBarList::TabProxyInfo * p = i->get(); + if( *p == m ) + { + f(p); + if( boolRemove ) + m_listTabProxyInfos.erase(i); + return true; + } + } + + return false; +} diff --git a/Console/TaskBarList.h b/Console/TaskBarList.h new file mode 100644 index 00000000..5fc503f7 --- /dev/null +++ b/Console/TaskBarList.h @@ -0,0 +1,84 @@ +#pragma once + +#include "ConsoleView.h" + +class TaskBarList +{ +public: + TaskBarList(void); + ~TaskBarList(void); + + void AddTab (ConsoleView* pConsoleView, HWND hwndMDI); + void RefreshTab (ConsoleView* pConsoleView); + void UpdateTabTitle (ConsoleView* pConsoleView); + void RemoveTab (ConsoleView* pConsoleView); + void SelectTab (ConsoleView* pConsoleView, HWND hwndMDI); +// void DragTab ... + + struct TabProxyInfo + { + TabProxyInfo(TaskBarList* pTaskBarList, ConsoleView* pConsoleView, ATOM atom, HICON hIconSm) + :pTaskBarList(pTaskBarList) + ,pConsoleView(pConsoleView) + ,hwndProxyTab(nullptr) + ,atom (atom) + ,hIconSm (hIconSm) + { + TRACE(L"TaskBarList::CreateTabProxy ptpi=%p, pTaskBarList=%p, pConsoleView=%p\n", this, pTaskBarList, pConsoleView); + } + + ~TabProxyInfo(void) + { + BOOL rc; + + if( hwndProxyTab ) + { + rc = CWindow(this->hwndProxyTab).DestroyWindow(); + ATLASSERT(rc != FALSE); + } + + rc = ::UnregisterClass( + reinterpret_cast(this->atom), + ::GetModuleHandle(nullptr)); + ATLASSERT(rc != FALSE); + + CIcon smallIcon(this->hIconSm); + } + + bool operator==(HWND hwndProxyTab) + { + return this->hwndProxyTab == hwndProxyTab; + } + + bool operator==(ConsoleView * pConsoleView) + { + return this->pConsoleView == pConsoleView; + } + + TaskBarList* pTaskBarList; + ConsoleView* pConsoleView; + HWND hwndProxyTab; + ATOM atom; + HICON hIconSm; + }; + +private: + HRESULT RegisterTab (HWND hwndTab, HWND hwndMDI); + HRESULT SetTabActive (HWND hwndTab, HWND hwndMDI); + HRESULT SetTabOrder (HWND hwndTab, HWND hwndInsertBefore); + HRESULT UnregisterTab (HWND hwndTab); + + template + inline bool Call (T m, const std::function & f, bool boolRemove = false); + + static ATOM RegisterTabProxyClass(const wchar_t * szClassName, HICON hIconSm); + HWND CreateTabProxy(ConsoleView* pConsoleView); + + static LRESULT CALLBACK TaskBarList::TabProxyWndProc(HWND hwnd,UINT Msg,WPARAM wParam,LPARAM lParam/*,int iTabId*/); + +private: + ATL::CComPtr m_taskBarList; + bool m_boolSupported; + std::list> m_listTabProxyInfos; +}; + diff --git a/Console/Todo.txt b/Console/Todo.txt deleted file mode 100644 index cff6418e..00000000 --- a/Console/Todo.txt +++ /dev/null @@ -1,36 +0,0 @@ -- handle maximize - -- handle full screen - -*** done *** - enclose drag 'n' dropped files with "s - -*** done *** - cursor rendering - -*** done *** - options dialog -*** done *** - tab settings - -*** done *** - image handler -*** done *** - basic stuff is working - -*** done *** - background rendering -*** done *** - in process -*** done *** - problems with relative backgrounds - -*** done *** - non-tabbed windows - -*** done *** - console: custom shell - -*** done *** - tabs: customize default console settings - -*** done *** - appearance: settings for view menu/toolbar/statusbar on startup - -- cursors: optimize painting for animated cursors - -*** done *** - About box: build number - -*** done *** - Toolbar: tooltips for buttons - -*** done *** - handle save crash - -- thread-safe tab switch - diff --git a/Console/Wallpaper.cpp b/Console/Wallpaper.cpp new file mode 100644 index 00000000..4f3b77f3 --- /dev/null +++ b/Console/Wallpaper.cpp @@ -0,0 +1,241 @@ +#include "StdAfx.h" +#include "WallPaper.h" + +#pragma warning(disable:4996) + +MyThread::MyThread(void) +:hStopSignalPtr(nullptr) +,hThreadPtr(nullptr) +,dwResult(0) +{ +} + +MyThread::~MyThread(void) +{ + try + { + this->Stop(INFINITE); + } + catch(std::exception&) + { + } +} + +void MyThread::Start(DWORD dwStackSize /*= 0*/) +{ + this->dwResult = 0; + + if( this->hThreadPtr.get() ) + throw std::exception("Thread is already running!"); + + this->hStopSignalPtr.reset(::CreateEvent(NULL, FALSE, FALSE, NULL)); + if( this->hStopSignalPtr.get() == nullptr ) + Win32Exception::ThrowFromLastError(); + + this->hThreadPtr.reset((HANDLE)_beginthreadex(0, dwStackSize, &_MyThreadFunction, (void*)this, 0, NULL)); + if( this->hThreadPtr.get() == nullptr ) + throw std::exception(_sys_errlist[errno]); +} + +DWORD MyThread::Stop(DWORD dwTimeout) +{ + try + { + if( this->hStopSignalPtr.get() ) + if( !SetEvent(this->hStopSignalPtr.get()) ) + Win32Exception::ThrowFromLastError(); + + if( this->hThreadPtr.get() ) + if( WaitForSingleObject(this->hThreadPtr.get(), dwTimeout) != WAIT_OBJECT_0 ) + Win32Exception::ThrowFromLastError(); + } + catch(std::exception&) + { + this->hStopSignalPtr.reset(); + this->hThreadPtr.reset(); + + throw; + } + + this->hStopSignalPtr.reset(); + this->hThreadPtr.reset(); + + return this->dwResult; +} + +unsigned int __stdcall _MyThreadFunction(void* arg) +{ + MyThread* pThread = static_cast(arg); + + try + { + pThread->dwResult = pThread->Process(pThread->hStopSignalPtr.get()); + } + catch(std::exception&) + { + pThread->dwResult = ~(DWORD)0; + } + + return 0; +} + +DWORD WallPaperThread::Process(HANDLE hStopSignal) +{ + HKEY hkey; + LSTATUS rc = ::RegOpenKeyEx( + HKEY_CURRENT_USER, + L"Control Panel\\Desktop", + 0, + KEY_READ, + &hkey); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + unique_ptrhkeyPtr(hkey); + + std::unique_ptrregkeyChangeNotification( + ::CreateEvent(NULL, FALSE, TRUE, NULL)); + if( regkeyChangeNotification.get() == nullptr ) + Win32Exception::ThrowFromLastError(); + + unique_ptrfolderChangeNotification(INVALID_HANDLE_VALUE); + + wchar_t szWallpaper[_MAX_PATH] = L""; + wchar_t szWallpaperStyle [16] = L""; + wchar_t szTileWallpaper [16] = L""; + long long llWallPaperFileSize = 0; + bool boolInit = true; + + for(bool loop = true; loop;) + { + bool boolCheckWallpaperChange = false; + bool boolWallpaperChangeHasChanged = false; + + HANDLE h[3] = {hStopSignal, regkeyChangeNotification.get(), folderChangeNotification.get()}; + switch( ::WaitForMultipleObjects(folderChangeNotification.get() == INVALID_HANDLE_VALUE?2:3, h, FALSE, INFINITE) ) + { + case WAIT_OBJECT_0: + loop = false; + break; + + case WAIT_OBJECT_0+1: + { + DWORD dwType; + DWORD dwValueSize; + + wchar_t szWallpaperTmp[_MAX_PATH]; + wchar_t szWallpaperStyleTmp[16]; + wchar_t szTileWallpaperTmp[16]; + + rc = ::RegQueryValueEx( + hkeyPtr.get(), + L"Wallpaper", + NULL, + &dwType, + (LPBYTE)szWallpaperTmp, &(dwValueSize = static_cast(sizeof(szWallpaperTmp)))); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + rc = ::RegQueryValueEx( + hkeyPtr.get(), + L"WallpaperStyle", + NULL, + &dwType, + (LPBYTE)szWallpaperStyleTmp, &(dwValueSize = static_cast(sizeof(szWallpaperStyleTmp)))); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + rc = ::RegQueryValueEx( + hkeyPtr.get(), + L"TileWallpaper", + NULL, + &dwType, + (LPBYTE)szTileWallpaperTmp, &(dwValueSize = static_cast(sizeof(szTileWallpaperTmp)))); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + + if( wcscmp(szWallpaperTmp, szWallpaper) || + wcscmp(szWallpaperStyleTmp, szWallpaperStyle) || + wcscmp(szTileWallpaperTmp, szTileWallpaper) ) + { + wcscpy_s(szWallpaper, szWallpaperTmp); + wcscpy_s(szWallpaperStyle, szWallpaperStyleTmp); + wcscpy_s(szTileWallpaper, szTileWallpaperTmp); + + // change the monitored directory + wchar_t szWallpaperFolder[_MAX_PATH]; + ::memcpy(szWallpaperFolder, szWallpaper, sizeof(szWallpaperFolder)); + ::PathRemoveFileSpec(szWallpaperFolder); + + folderChangeNotification.reset( + ::FindFirstChangeNotification( + szWallpaperFolder, + FALSE, + FILE_NOTIFY_CHANGE_SIZE)); + + if( folderChangeNotification.get() == INVALID_HANDLE_VALUE ) + Win32Exception::ThrowFromLastError(); + + if( !boolInit ) + boolWallpaperChangeHasChanged = true; + } + + // reactive registry monitoring + rc = ::RegNotifyChangeKeyValue( + hkeyPtr.get(), + FALSE, + REG_NOTIFY_CHANGE_LAST_SET, + regkeyChangeNotification.get(), + TRUE + ); + + if( rc != ERROR_SUCCESS ) + Win32Exception::Throw(rc); + } + break; + + case WAIT_OBJECT_0+2: + { + // reactive directory monitoring + if( !::FindNextChangeNotification(folderChangeNotification.get()) ) + Win32Exception::ThrowFromLastError(); + + boolCheckWallpaperChange = true; + } + break; + } + + if( boolWallpaperChangeHasChanged || boolCheckWallpaperChange || boolInit ) + { + _stat64 theStat; + if( _wstat64(szWallpaper, &theStat) ) + throw std::exception(_sys_errlist[errno]); + + if( boolInit ) + boolInit = false; + + if( boolCheckWallpaperChange ) + { + if( theStat.st_size && llWallPaperFileSize != theStat.st_size ) + boolWallpaperChangeHasChanged = true; + } + + if( boolWallpaperChangeHasChanged ) + { + TRACE(L"wallpaper = %s style = %s\n", szWallpaper, szWallpaperStyle); + // delay the message sending: desktop black / not ready + ::Sleep(100); + if( ::IsWindow(m_mainFrame.m_hWnd) ) + m_mainFrame.SendMessageW(WM_SETTINGCHANGE, 0, (LPARAM)L"intl"); + } + + llWallPaperFileSize = theStat.st_size; + } + } + + return 0; +} \ No newline at end of file diff --git a/Console/Wallpaper.h b/Console/Wallpaper.h new file mode 100644 index 00000000..47eebff9 --- /dev/null +++ b/Console/Wallpaper.h @@ -0,0 +1,33 @@ +#pragma once + +#include "MainFrame.h" + +class MyThread +{ +public: + MyThread (void); + virtual ~MyThread (void); + + void Start (DWORD dwStackSize = 0); + DWORD Stop (DWORD dwTimeout); + virtual DWORD Process (HANDLE hStopSignal) = 0; + +private: + std::unique_ptr hStopSignalPtr; + std::unique_ptr hThreadPtr; + DWORD dwResult; + + friend unsigned int __stdcall _MyThreadFunction (void*); +}; + + +class WallPaperThread : public MyThread +{ + MainFrame& m_mainFrame; + +public: + WallPaperThread (MainFrame& mainFrame):m_mainFrame(mainFrame) {} + virtual ~WallPaperThread (void) {} + + virtual DWORD Process (HANDLE hStopSignal); +}; diff --git a/Console/XmlHelper.cpp b/Console/XmlHelper.cpp index e0a3e081..7aedb9cc 100644 --- a/Console/XmlHelper.cpp +++ b/Console/XmlHelper.cpp @@ -198,7 +198,7 @@ void XmlHelper::GetRGBAttribute(const CComPtr& pElement, COLORRE void XmlHelper::SetAttribute(const CComPtr& pElement, const CComBSTR& bstrName, DWORD dwValue) { - CComVariant varValue(str(wformat(L"%1%") % dwValue).c_str()); + CComVariant varValue(boost::str(boost::wformat(L"%1%") % dwValue).c_str()); pElement->setAttribute(bstrName, varValue); } @@ -210,7 +210,7 @@ void XmlHelper::SetAttribute(const CComPtr& pElement, const CCom void XmlHelper::SetAttribute(const CComPtr& pElement, const CComBSTR& bstrName, int nValue) { - CComVariant varValue(str(wformat(L"%1%") % nValue).c_str()); + CComVariant varValue(boost::str(boost::wformat(L"%1%") % nValue).c_str()); pElement->setAttribute(bstrName, varValue); } @@ -222,7 +222,7 @@ void XmlHelper::SetAttribute(const CComPtr& pElement, const CCom void XmlHelper::SetAttribute(const CComPtr& pElement, const CComBSTR& bstrName, BYTE byValue) { - CComVariant varValue(str(wformat(L"%1%") % byValue).c_str()); + CComVariant varValue(boost::str(boost::wformat(L"%1%") % byValue).c_str()); pElement->setAttribute(bstrName, varValue); } diff --git a/Console/console.xml b/Console/console.xml deleted file mode 100644 index 3bf1babb..00000000 --- a/Console/console.xml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Console/res/Console.ico b/Console/res/Console.ico index 0b6dc468..5dfa2881 100644 Binary files a/Console/res/Console.ico and b/Console/res/Console.ico differ diff --git a/Console/res/toolbar_aero.bmp b/Console/res/toolbar_aero.bmp new file mode 100644 index 00000000..0744fca9 Binary files /dev/null and b/Console/res/toolbar_aero.bmp differ diff --git a/Console/resource.h b/Console/resource.h index e9491450..c861f508 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -1,244 +1,292 @@ -//{{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_TYPE1 1069 -#define IDC_TRANSPARENCY_TYPE2 1070 -#define IDC_TRANSPARENCY_TYPE3 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 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 215 -#define _APS_NEXT_COMMAND_VALUE 32794 -#define _APS_NEXT_CONTROL_VALUE 1172 -#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 IDPANE_CAPS_INDICATOR 130 +#define IDPANE_NUM_INDICATOR 131 +#define IDPANE_SCRL_INDICATOR 132 +#define IDPANE_PID_INDICATOR 133 +#define IDPANE_SELECTION 134 +#define IDPANE_COLUMNS_ROWS 135 +#define IDPANE_BUF_COLUMNS_ROWS 136 + +#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 IDD_CREDENTIALS 216 +#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_FLAT_SCROLLBARS 1095 +#define IDC_RADIO_DOCK_TL 1096 +#define IDC_CHECK_STYLE_QUAKE 1096 +#define IDC_RADIO_DOCK_TR 1097 +#define IDC_CHECK_USE_JUMPLIST 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_TRIM_TAB_TITLES_RIGHT 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_SPIN_TRIM_TAB_TITLES_RIGHT 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_CURSOR_ANIM 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_BTN_CLONE 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_SENSITIVE_COPY 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 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_CHECK_DEFAULT_ICON 1172 +#define IDC_CHECK_TABS_ON_BOTTOM 1173 +#define IDC_TAB_USER 1174 +#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 +#define IDC_STATIC_PASSWORD 1178 +#define IDC_BGTEXT_OPACITY 1179 +#define IDC_BGTEXT_OPACITY_VAL 1180 +#define IDC_STATIC_BGTEXT_OPACITY 1181 +#define IDC_CHECK_NET_ONLY 1182 +#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 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_SHELL_AS_USER 5001 +#define IDS_ERR_DLL_INJECTION_FAILED 5002 +#define IDS_ERR_DLL_HOOK_MISSING 5003 +#define IDS_ERR_CREATE_SHARED_OBJECTS_FAILED 5004 +#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 +#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_STOP_SCROLLING 32792 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 217 +#define _APS_NEXT_COMMAND_VALUE 32793 +#define _APS_NEXT_CONTROL_VALUE 1183 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Console/stdafx.h b/Console/stdafx.h index 5b1349b8..9d123dad 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -6,10 +6,15 @@ #pragma once // Change these values to use different versions -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 -#define _WIN32_IE 0x0400 -#define _RICHEDIT_VER 0x0100 +#define WINVER 0x0601 +#define _WIN32_WINNT 0x0601 +#ifdef _USE_AERO +#define _WIN32_IE 0x0700 +#define _RICHEDIT_VER 0x0200 +#else +#define _WIN32_IE 0x0400 +#define _RICHEDIT_VER 0x0100 +#endif ////////////////////////////////////////////////////////////////////////////// @@ -39,21 +44,46 @@ 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 + +#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" -//#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 "multisplit.h" #include +#include +#ifdef _USE_AERO +#include +#include +#endif #pragma warning(disable: 4503) // disables 'name truncated' warnings @@ -69,12 +99,10 @@ using namespace std; #pragma warning(push) #pragma warning(disable: 4244 4267 4511 4512 701 4702) -#include #include #include #include #include -using namespace boost; #pragma warning(pop) #pragma warning(push) @@ -89,6 +117,8 @@ using namespace boost::multi_index; #include "../shared/SharedMemory.h" #include "../shared/Structures.h" +#include "../shared/Cpp11Helpers.h" +#include "../shared/Win32Exception.h" #include "Helpers.h" #include "ConsoleHandler.h" #include "ImageHandler.h" @@ -105,9 +135,7 @@ using namespace boost::multi_index; ////////////////////////////////////////////////////////////////////////////// // Version numbers -#define VERSION_MAJOR 2 -#define VERSION_MINOR 0 -#define VERSION_BUILD 146 +#include "../shared/version.h" ////////////////////////////////////////////////////////////////////////////// @@ -132,6 +160,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 ////////////////////////////////////////////////////////////////////////////// @@ -159,6 +190,15 @@ using namespace boost::multi_index; ////////////////////////////////////////////////////////////////////////////// + +typedef enum +{ + ADJUSTSIZE_NONE, + ADJUSTSIZE_WINDOW, + ADJUSTSIZE_FONT +} +ADJUSTSIZE; + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/wtlaero.h b/Console/wtlaero.h new file mode 100644 index 00000000..95672292 --- /dev/null +++ b/Console/wtlaero.h @@ -0,0 +1,1594 @@ +// 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(); +} + +extern bool _bAeroGlassActive; +__declspec(selectany) bool _bAeroGlassActive = true; + +inline void SetAeroGlassActive(bool bAeroGlassActive) +{ + _bAeroGlassActive = bAeroGlassActive; +} + +inline bool IsComposing() +{ + if( !_bAeroGlassActive ) return false; + + 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..23cc4650 100644 --- a/Console2.sln +++ b/Console2.sln @@ -1,41 +1,74 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleHook", "ConsoleHook\ConsoleHook.vcproj", "{69234D74-7133-48FF-8DDB-9901FFC4D7FF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "Console\Console.vcproj", "{6EA5C354-A242-49F3-88D1-559EACA7FB8A}" -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 -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug|Win32.ActiveCfg = Debug|Win32 - {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|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 - {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release|x64.Build.0 = Release|x64 - {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug|Win32.ActiveCfg = Debug|Win32 - {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|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 - {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA1A8A1D-90C0-49B9-A9B2-DF2C574F19E6}" + ProjectSection(SolutionItems) = preProject + todo.txt = todo.txt + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleHook", "ConsoleHook\ConsoleHook.vcxproj", "{69234D74-7133-48FF-8DDB-9901FFC4D7FF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "Console\Console.vcxproj", "{6EA5C354-A242-49F3-88D1-559EACA7FB8A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleWow", "ConsoleWow\ConsoleWow.vcxproj", "{8A25E8AF-CC4A-4145-B878-3D99271562D4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug aero|Win32 = Debug aero|Win32 + Debug aero|x64 = Debug aero|x64 + 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 + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug aero|Win32.ActiveCfg = Debug aero|Win32 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug aero|Win32.Build.0 = Debug aero|Win32 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug aero|x64.ActiveCfg = Debug aero|x64 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug aero|x64.Build.0 = Debug aero|x64 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {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 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release|x64.Build.0 = Release|x64 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug aero|Win32.ActiveCfg = Debug aero|Win32 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug aero|Win32.Build.0 = Debug aero|Win32 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug aero|x64.ActiveCfg = Debug aero|x64 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug aero|x64.Build.0 = Debug aero|x64 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug|Win32.ActiveCfg = Debug|Win32 + {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 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|x64.Build.0 = Release|x64 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug aero|Win32.ActiveCfg = Debug aero|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug aero|x64.ActiveCfg = Debug aero|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug aero|x64.Build.0 = Debug aero|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug|x64.ActiveCfg = Debug|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug|x64.Build.0 = Debug|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release aero|Win32.ActiveCfg = Release aero|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release aero|x64.ActiveCfg = Release aero|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release aero|x64.Build.0 = Release aero|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release|Win32.ActiveCfg = Release|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release|x64.ActiveCfg = Release|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release|x64.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 57141885..ac70ba1a 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" using namespace std; -using namespace boost; #include "../shared/SharedMemNames.h" #include "ConsoleHandler.h" @@ -16,18 +15,17 @@ using namespace boost; ////////////////////////////////////////////////////////////////////////////// ConsoleHandler::ConsoleHandler() -: m_hParentProcess() -, m_consoleParams() +: m_consoleParams() , m_consoleInfo() , m_cursorInfo() , m_consoleBuffer() , m_consoleCopyInfo() -, m_consolePasteInfo() +, m_consoleTextInfo() , m_consoleMouseEvent() , m_newConsoleSize() , m_newScrollPos() , m_hMonitorThread() -, m_hMonitorThreadExit(shared_ptr(::CreateEvent(NULL, FALSE, FALSE, NULL), ::CloseHandle)) +, m_hMonitorThreadExit(std::shared_ptr(::CreateEvent(NULL, FALSE, FALSE, NULL), ::CloseHandle)) , m_dwScreenBufferSize(0) { } @@ -50,7 +48,7 @@ ConsoleHandler::~ConsoleHandler() DWORD ConsoleHandler::StartMonitorThread() { DWORD dwThreadId = 0; - m_hMonitorThread = shared_ptr( + m_hMonitorThread = std::shared_ptr( ::CreateThread( NULL, 0, @@ -86,37 +84,45 @@ void ConsoleHandler::StopMonitorThread() bool ConsoleHandler::OpenSharedObjects() { - // open startup params memory object - DWORD dwProcessId = ::GetCurrentProcessId(); + try + { + // open startup params memory object + DWORD dwProcessId = ::GetCurrentProcessId(); - // TODO: error handling - m_consoleParams.Open((SharedMemNames::formatConsoleParams % dwProcessId).str(), syncObjRequest); + // TODO: error handling + m_consoleParams.Open((SharedMemNames::formatConsoleParams % dwProcessId).str(), syncObjRequest); - // open console info shared memory object - m_consoleInfo.Open((SharedMemNames::formatInfo % dwProcessId).str(), syncObjRequest); + // open console info shared memory object + m_consoleInfo.Open((SharedMemNames::formatInfo % dwProcessId).str(), syncObjRequest); - // open console info shared memory object - m_cursorInfo.Open((SharedMemNames::formatCursorInfo % dwProcessId).str(), syncObjRequest); + // open console info shared memory object + m_cursorInfo.Open((SharedMemNames::formatCursorInfo % dwProcessId).str(), syncObjRequest); - // open console buffer shared memory object - m_consoleBuffer.Open((SharedMemNames::formatBuffer % dwProcessId).str(), syncObjRequest); + // open console buffer shared memory object + m_consoleBuffer.Open((SharedMemNames::formatBuffer % dwProcessId).str(), syncObjRequest); - // copy info - m_consoleCopyInfo.Open((SharedMemNames::formatCopyInfo % dwProcessId).str(), syncObjBoth); + // 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); + // mouse event + m_consoleMouseEvent.Open((SharedMemNames::formatMouseEvent % dwProcessId).str(), syncObjBoth); - // open new console size shared memory object - m_newConsoleSize.Open((SharedMemNames::formatNewConsoleSize % dwProcessId).str(), syncObjRequest); + // open new console size shared memory object + m_newConsoleSize.Open((SharedMemNames::formatNewConsoleSize % dwProcessId).str(), syncObjRequest); - // new scroll position - m_newScrollPos.Open((SharedMemNames::formatNewScrollPos % dwProcessId).str(), syncObjRequest); + // new scroll position + m_newScrollPos.Open((SharedMemNames::formatNewScrollPos % dwProcessId).str(), syncObjRequest); + } + catch(Win32Exception& ex) + { + fprintf(stderr, "/!\\ ConsoleZ: can't open shared objects (reason: %s)\n", ex.what()); + return false; + } - return true; + return true; } ////////////////////////////////////////////////////////////////////////////// @@ -128,37 +134,46 @@ 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( - L"CONOUT$", - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - 0), - ::CloseHandle); + // no need to call CloseHandle when done, we're reusing console handles + std::unique_ptr hStdOut(::CreateFile( + L"CONOUT$", + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + 0)); + + if( hStdOut.get() == INVALID_HANDLE_VALUE ) + { + Win32Exception err(::GetLastError()); + TRACE(L"CreateFile returns error (%lu) : %S\n", err.GetErrorCode(), err.what()); + return; + } - // get total console size CONSOLE_SCREEN_BUFFER_INFO csbiConsole; COORD coordConsoleSize; - ::GetConsoleScreenBufferInfo(hStdOut.get(), &csbiConsole); + if( !::GetConsoleScreenBufferInfo(hStdOut.get(), &csbiConsole) ) + { + Win32Exception err(::GetLastError()); + TRACE(L"GetConsoleScreenBufferInfo(%p) returns error (%lu) : %S\n", hStdOut.get(), err.GetErrorCode(), err.what()); + return; + } coordConsoleSize.X = csbiConsole.srWindow.Right - csbiConsole.srWindow.Left + 1; coordConsoleSize.Y = csbiConsole.srWindow.Bottom - csbiConsole.srWindow.Top + 1; -/* + TRACE(L"ReadConsoleBuffer console buffer size: %ix%i\n", csbiConsole.dwSize.X, csbiConsole.dwSize.Y); TRACE(L"ReadConsoleBuffer console rect: %ix%i - %ix%i\n", csbiConsole.srWindow.Left, csbiConsole.srWindow.Top, csbiConsole.srWindow.Right, csbiConsole.srWindow.Bottom); TRACE(L"console window rect: (%i, %i) - (%i, %i)\n", csbiConsole.srWindow.Top, csbiConsole.srWindow.Left, csbiConsole.srWindow.Bottom, csbiConsole.srWindow.Right); -*/ // do console output buffer reading DWORD dwScreenBufferSize = coordConsoleSize.X * coordConsoleSize.Y; DWORD dwScreenBufferOffset= 0; - shared_array pScreenBuffer(new CHAR_INFO[dwScreenBufferSize]); + std::unique_ptr pScreenBuffer(new CHAR_INFO[dwScreenBufferSize]); COORD coordBufferSize; // start coordinates for the buffer are always (0, 0) - we use offset @@ -224,16 +239,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(); @@ -251,7 +275,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); @@ -259,6 +289,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; @@ -297,13 +331,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; @@ -315,13 +349,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; @@ -329,11 +363,27 @@ 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); } } + 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) { @@ -343,13 +393,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; @@ -361,13 +411,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; @@ -375,11 +425,27 @@ 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); } } + 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); @@ -431,8 +497,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); @@ -443,6 +512,271 @@ 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) + { + boost::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 ++) + { + char szColor[64]; + _snprintf_s( + szColor, sizeof(szColor), + _TRUNCATE, + "\\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_s( + szFont, sizeof(szFont), + _TRUNCATE, + "\\f0\\fs%lu%s%s\n", + pconsoleCopy->dwSize, + pconsoleCopy->bBold ? "\\b" : "", + pconsoleCopy->bItalic ? "\\i" : ""); + + strRtf += szFont; + } + virtual ~ClipboardDataRtf(void) {} + virtual void StartRow(void) + { + strRowRtf.clear(); + sizeRowLen = 0; + } + virtual void EndRow(void) + { + strRtf += strRowRtf; + strRtf += strTrimRowRtf; + strTrimRowRtf.clear(); + } + 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; + } + + bool trim = std::isspace(p->Char.UnicodeChar, std::locale()); + + std::string& strRowRtfRef = (trim)?strTrimRowRtf:strRowRtf; + if( trim ) + { + if( strTrimRowRtf.empty() ) + { + wLastTrimCharForegroundAttributes = wLastCharForegroundAttributes; + wLastTrimCharBackgroundAttributes = wLastCharBackgroundAttributes; + } + } + else + { + strRowRtf += strTrimRowRtf; + strTrimRowRtf.clear(); + } + + if( wLastCharBackgroundAttributes != wCharBackgroundAttributes ) + { + _snprintf_s( + szDummy, sizeof(szDummy), + _TRUNCATE, + "\\highlight%hu ", + wCharBackgroundAttributes); + strRowRtfRef += szDummy; + } + if( wLastCharForegroundAttributes != wCharForegroundAttributes ) + { + _snprintf_s( + szDummy, sizeof(szDummy), + _TRUNCATE, + "\\cf%hu ", + wCharForegroundAttributes); + strRowRtfRef += szDummy; + } + wLastCharForegroundAttributes = wCharForegroundAttributes; + wLastCharBackgroundAttributes = wCharBackgroundAttributes; + + WCHAR wc = p->Char.UnicodeChar; + if( wc == L'\\' ) strRowRtfRef += "\\\\"; + else if( wc == L'{' ) strRowRtfRef += "\\{"; + else if( wc == L'}' ) strRowRtfRef += "\\}"; + else if( wc <= 0x7f ) strRowRtfRef += p->Char.AsciiChar; + else + { + _snprintf_s(szDummy, sizeof(szDummy), _TRUNCATE, "\\u%d?", wc); + strRowRtfRef += szDummy; + } + sizeRowLen ++; + sizeRtfLen ++; + } + virtual bool IsLastCharBlank(void) + { + return !strTrimRowRtf.empty(); + } + size_t GetRowLength(void) + { + return sizeRowLen; + } + virtual void TrimRight(void) + { + if( !strTrimRowRtf.empty() ) + { + strTrimRowRtf.clear(); + wLastCharForegroundAttributes = wLastTrimCharForegroundAttributes; + wLastCharBackgroundAttributes = wLastTrimCharBackgroundAttributes; + } + } + virtual void Wrap(CopyNewlineChar /*copyNewlineChar*/) + { + strTrimRowRtf += "\\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 strRowRtf; + string strTrimRowRtf; + size_t sizeRtfLen; + size_t sizeRowLen; + WORD wLastCharForegroundAttributes; + WORD wLastCharBackgroundAttributes; + WORD wLastTrimCharForegroundAttributes; + WORD wLastTrimCharBackgroundAttributes; +}; + void ConsoleHandler::CopyConsoleText() { if (!::OpenClipboard(NULL)) return; @@ -452,7 +786,7 @@ void ConsoleHandler::CopyConsoleText() // TRACE(L"Copy request: %ix%i - %ix%i\n", coordStart.X, coordStart.Y, coordEnd.X, coordEnd.Y); - shared_ptr hStdOut( + std::shared_ptr hStdOut( ::CreateFile( L"CONOUT$", GENERIC_WRITE | GENERIC_READ, @@ -463,18 +797,49 @@ void ConsoleHandler::CopyConsoleText() 0), ::CloseHandle); - // get total console size - CONSOLE_SCREEN_BUFFER_INFO csbiConsole; - wstring strText(L""); - - ::GetConsoleScreenBufferInfo(hStdOut.get(), &csbiConsole); + auto_ptr clipboardDataPtr[2]; + size_t clipboardDataCount = 2; + clipboardDataPtr[0].reset(new ClipboardDataUnicode()); + clipboardDataPtr[1].reset(new ClipboardDataRtf(m_consoleCopyInfo.Get())); + + COORD coordFrom = {0, 0}; + COORD coordBufferSize = {(m_consoleParams->dwBufferColumns > 0) ? static_cast(m_consoleParams->dwBufferColumns) : static_cast(m_consoleParams->dwColumns), 1}; + std::unique_ptr pScreenBuffer(new CHAR_INFO[coordBufferSize.X]); + + // suppress end empty lines + bool emptyLine = true; + for (SHORT i = coordEnd.Y; i > coordStart.Y && emptyLine; --i) + { + SMALL_RECT srBuffer; + + srBuffer.Left = 0; + srBuffer.Top = i; + srBuffer.Right = (i == coordEnd.Y) ? coordEnd.X : (m_consoleParams->dwBufferColumns > 0) ? static_cast(m_consoleParams->dwBufferColumns - 1) : static_cast(m_consoleParams->dwColumns - 1); + srBuffer.Bottom = i; + + ::ReadConsoleOutput( + hStdOut.get(), + pScreenBuffer.get(), + coordBufferSize, + coordFrom, + &srBuffer); + + for (SHORT x = 0; x <= srBuffer.Right - srBuffer.Left && emptyLine; ++x) + { + if( pScreenBuffer[x].Char.UnicodeChar != L' ' ) + emptyLine = false; + } + + if( emptyLine ) + { + coordEnd.Y --; + coordEnd.X = coordBufferSize.X - 1; + } + } for (SHORT i = coordStart.Y; i <= coordEnd.Y; ++i) { SMALL_RECT srBuffer; - COORD coordFrom = {0, 0}; - COORD coordBufferSize = {(m_consoleParams->dwBufferColumns > 0) ? static_cast(m_consoleParams->dwBufferColumns) : static_cast(m_consoleParams->dwColumns), 1}; - shared_array pScreenBuffer(new CHAR_INFO[coordBufferSize.X]); // TRACE(L"i: %i, coordStart.Y: %i, coordStart.X: %i\n", i, coordStart.Y, coordStart.X); srBuffer.Left = (i == coordStart.Y) ? coordStart.X : 0; @@ -495,13 +860,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 @@ -517,7 +885,7 @@ void ConsoleHandler::CopyConsoleText() && (coordStart.Y < coordEnd.Y) && - (strRow[strRow.length() - 1] != L' ') + (!clipboardDataPtr[0]->IsLastCharBlank()) ) ) { @@ -527,7 +895,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; } @@ -535,47 +903,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; - } - - ::EmptyClipboard(); + for(size_t clipboardDataIndex = 0; clipboardDataIndex < clipboardDataCount; clipboardDataIndex ++) + { + if (m_consoleCopyInfo->bTrimSpaces) + clipboardDataPtr[clipboardDataIndex]->TrimRight(); - HGLOBAL hText = ::GlobalAlloc(GMEM_MOVEABLE, (strText.length()+1)*sizeof(wchar_t)); + if (bWrap) + clipboardDataPtr[clipboardDataIndex]->Wrap(m_consoleCopyInfo->copyNewlineChar); - if (hText == NULL) - { - ::CloseClipboard(); - return; - } + clipboardDataPtr[clipboardDataIndex]->EndRow(); + } + } - ::CopyMemory(static_cast(::GlobalLock(hText)), strText.c_str(), (strText.length()+1)*sizeof(wchar_t)); + ::EmptyClipboard(); - ::GlobalUnlock(hText); + for(size_t clipboardDataIndex = 0; clipboardDataIndex < clipboardDataCount; clipboardDataIndex ++) + clipboardDataPtr[clipboardDataIndex]->Publish(); - 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 } ////////////////////////////////////////////////////////////////////////////// @@ -583,110 +935,14 @@ void ConsoleHandler::CopyConsoleText() ////////////////////////////////////////////////////////////////////////////// -void ConsoleHandler::PasteConsoleText(HANDLE hStdIn, const shared_ptr& pszPasteBuffer) +void ConsoleHandler::SendConsoleText(HANDLE hStdIn, const std::shared_ptr& textBuffer) { - wchar_t* pszText = NULL; - HANDLE hData = NULL; + wchar_t* pszText = textBuffer.get(); + size_t textLen = wcslen(pszText); + size_t partLen = 512; + size_t parts = textLen/partLen; + size_t offset = 0; - 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; - - ++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; @@ -697,23 +953,13 @@ void ConsoleHandler::PasteConsoleText(HANDLE hStdIn, const shared_ptr& partLen = textLen - parts*partLen; } - scoped_array pKeyEvents(new INPUT_RECORD[partLen]); + std::unique_ptr pKeyEvents(new INPUT_RECORD[partLen]); ::ZeroMemory(pKeyEvents.get(), sizeof(INPUT_RECORD)*partLen); for (size_t i = 0; (i < partLen) && (offset < textLen); ++i, ++offset, ++keyEventCount) { 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,70 +993,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); -// } -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void ConsoleHandler::SetResetKeyInput(scoped_array& kbdInputs, WORD wVk, short& sCount) -{ - if ((::GetAsyncKeyState(wVk) & 0x8000) != 0) - { - kbdInputs[sCount].type = INPUT_KEYBOARD; - kbdInputs[sCount].ki.wVk = wVk; - kbdInputs[sCount].ki.dwFlags = KEYEVENTF_KEYUP; - ++sCount; - } -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -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; } ////////////////////////////////////////////////////////////////////////////// @@ -889,7 +1071,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(); @@ -924,110 +1106,61 @@ 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(PROCESS_ALL_ACCESS, FALSE, m_consoleParams->dwParentProcessId), - ::CloseHandle); - - 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()); - - ::SuspendThread(GetCurrentThread()); - - ResizeConsoleWindow(hStdOut.get(), m_consoleParams->dwColumns, m_consoleParams->dwRows, 0); + 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); + + if (::WaitForSingleObject(m_consoleParams.GetRespEvent(), 10000) == WAIT_TIMEOUT) return 0; + + ResizeConsoleWindow(hStdOut, m_consoleParams->dwColumns, m_consoleParams->dwRows, 0); // FIX: this seems to case problems on startup // ReadConsoleBuffer(); + std::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[] = { m_hMonitorThreadExit.get(), -// hStdErr, m_consoleCopyInfo.GetReqEvent(), - m_consolePasteInfo.GetReqEvent(), + m_consoleTextInfo.GetReqEvent(), m_newScrollPos.GetReqEvent(), m_consoleMouseEvent.GetReqEvent(), m_newConsoleSize.GetReqEvent(), - hStdOut.get(), - m_hParentProcess.get() + hStdOut, }; 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 (dwWaitRes == WAIT_FAILED) + if ((parentProcessWatchdog.get() != NULL) && (::WaitForSingleObject(parentProcessWatchdog.get(), 0) == WAIT_ABANDONED)) { - 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"); - } - + TRACE(L"Watchdog 0x%08X died. Time to exit", parentProcessWatchdog.get()); + ::SendMessage(m_consoleParams->hwndConsoleWindow, WM_CLOSE, 0, 0); + break; } -*/ switch (dwWaitRes) { @@ -1041,22 +1174,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; + std::shared_ptr textBuffer; - if (*m_consolePasteInfo.Get() != NULL) + if (m_consoleTextInfo->mem != NULL) { - pszPasteBuffer.reset( - reinterpret_cast(*m_consolePasteInfo.Get()), - bind(::VirtualFreeEx, ::GetCurrentProcess(), _1, NULL, MEM_RELEASE)); + textBuffer.reset( + reinterpret_cast(m_consoleTextInfo->mem), + boost::bind(::VirtualFreeEx, ::GetCurrentProcess(), _1, NULL, MEM_RELEASE)); } - PasteConsoleText(hStdIn.get(), pszPasteBuffer); - m_consolePasteInfo.SetRespEvent(); + SendConsoleText(hStdIn, textBuffer); + m_consoleTextInfo.SetRespEvent(); break; } @@ -1065,7 +1198,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 +1208,7 @@ DWORD ConsoleHandler::MonitorThread() { SharedMemoryLock memLock(m_consoleMouseEvent); - SendMouseEvent(hStdIn.get()); + SendMouseEvent(hStdIn); m_consoleMouseEvent.SetRespEvent(); break; } @@ -1085,13 +1218,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 @@ -1102,12 +1234,6 @@ 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; - } } diff --git a/ConsoleHook/ConsoleHandler.h b/ConsoleHook/ConsoleHandler.h index 5493a713..aeef1c06 100644 --- a/ConsoleHook/ConsoleHandler.h +++ b/ConsoleHook/ConsoleHandler.h @@ -31,11 +31,7 @@ class ConsoleHandler void CopyConsoleText(); - void PasteConsoleText(HANDLE hStdIn, const shared_ptr& pszPasteBuffer); - - void SetResetKeyInput(scoped_array& kbdInputs, WORD wVk, short& sCount); - - void WriteConsoleInput(HANDLE hStdIn, scoped_array& consoleInputs, size_t& consoleInputCount, size_t maxConsoleInputCount); + void SendConsoleText(HANDLE hStdIn, const std::shared_ptr& textBuffer); void SendMouseEvent(HANDLE hStdIn); @@ -50,21 +46,19 @@ class ConsoleHandler private: - shared_ptr m_hParentProcess; - SharedMemory m_consoleParams; - SharedMemory m_consoleInfo; + SharedMemory m_consoleInfo; SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; - SharedMemory m_consolePasteInfo; + SharedMemory m_consoleTextInfo; SharedMemory m_consoleMouseEvent; SharedMemory m_newConsoleSize; SharedMemory m_newScrollPos; - shared_ptr m_hMonitorThread; - shared_ptr m_hMonitorThreadExit; + std::shared_ptr m_hMonitorThread; + std::shared_ptr m_hMonitorThreadExit; DWORD m_dwScreenBufferSize; }; diff --git a/ConsoleHook/ConsoleHook.cpp b/ConsoleHook/ConsoleHook.cpp index 14ace79c..2484a7de 100644 --- a/ConsoleHook/ConsoleHook.cpp +++ b/ConsoleHook/ConsoleHook.cpp @@ -19,8 +19,8 @@ ConsoleHandler g_consoleHandler; BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID /* lpReserved */) { - TRACE(L"DLL main!\n"); - + TRACE(L"DLL main! reason %lu\n", ul_reason_for_call); + switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: diff --git a/ConsoleHook/ConsoleHook.rc b/ConsoleHook/ConsoleHook.rc index 8780db11..908c7c4b 100644 --- a/ConsoleHook/ConsoleHook.rc +++ b/ConsoleHook/ConsoleHook.rc @@ -1,6 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" +#include "../shared/version.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -53,8 +54,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,146 - PRODUCTVERSION 2,0,0,146 + FILEVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD2 + PRODUCTVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD2 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,16 +70,15 @@ BEGIN BEGIN BLOCK "000004b0" 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 "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 "Comments", "Tabbed cool console window (THIS IS NOT A SHELL :-)" + VALUE "FileDescription", "Console process hook module" + VALUE "FileVersion", VERSION_FILE + VALUE "InternalName", "ConsoleZ" + VALUE "LegalCopyright", VERSION_COPYRIGHT + VALUE "LegalTrademarks", VERSION_COPYRIGHT + VALUE "OriginalFilename", "ConsoleHook.dll" + VALUE "ProductName", "ConsoleZ" + VALUE "ProductVersion", VERSION_PRODUCT END END BLOCK "VarFileInfo" diff --git a/ConsoleHook/ConsoleHook.vcproj b/ConsoleHook/ConsoleHook.vcproj deleted file mode 100644 index 26dd3176..00000000 --- a/ConsoleHook/ConsoleHook.vcproj +++ /dev/null @@ -1,441 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ConsoleHook/ConsoleHook.vcxproj b/ConsoleHook/ConsoleHook.vcxproj new file mode 100644 index 00000000..69f0b90f --- /dev/null +++ b/ConsoleHook/ConsoleHook.vcxproj @@ -0,0 +1,445 @@ + + + + + Debug aero + Win32 + + + Debug aero + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release aero + Win32 + + + Release aero + x64 + + + Release + Win32 + + + Release + x64 + + + + {69234D74-7133-48FF-8DDB-9901FFC4D7FF} + ConsoleHook + Win32Proj + + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + DynamicLibrary + Unicode + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + ..\bin\$(Platform)\$(Configuration)\ + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + true + true + ..\bin\$(Platform)\$(Configuration)\ + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + true + true + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + ..\bin\$(Platform)\$(Configuration)\ + ..\obj\$(Platform)\$(ProjectName)\$(Configuration)\ + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + + + + Disabled + WIN32;_WINDOWS;_USRDLL;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + $(OutDir)ConsoleHook.pdb + Windows + false + + + $(OutDir)ConsoleHook.lib + MachineX86 + + + copy "..\bin\$(Platform)\$(Configuration)\ConsoleHook.dll" "..\bin\x64\$(Configuration)\ConsoleHook32.dll" + + + + + Disabled + WIN32;_WINDOWS;_USRDLL;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + $(OutDir)ConsoleHook.pdb + Windows + false + + + $(OutDir)ConsoleHook.lib + MachineX86 + + + copy "..\bin\$(Platform)\$(Configuration)\ConsoleHook.dll" "..\bin\x64\$(Configuration)\ConsoleHook32.dll" + + + + + X64 + + + Disabled + WIN32;_WINDOWS;_USRDLL;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + $(OutDir)ConsoleHook.pdb + Windows + false + + + $(OutDir)ConsoleHook.lib + MachineX64 + + + + + X64 + + + Disabled + WIN32;_WINDOWS;_USRDLL;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + $(OutDir)ConsoleHook.pdb + Windows + false + + + $(OutDir)ConsoleHook.lib + MachineX64 + + + + + WIN32;_WINDOWS;_USRDLL;NDEBUG;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + Windows + true + true + false + + + $(OutDir)ConsoleHook.lib + MachineX86 + + + copy "..\bin\$(Platform)\$(Configuration)\ConsoleHook.dll" "..\bin\x64\$(Configuration)\ConsoleHook32.dll" + + + + + X64 + + + WIN32;_WINDOWS;_USRDLL;NDEBUG;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + Windows + true + true + false + + + $(OutDir)ConsoleHook.lib + MachineX64 + + + + + WIN32;_WINDOWS;_USRDLL;NDEBUG;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + Windows + true + true + false + + + $(OutDir)ConsoleHook.lib + MachineX86 + + + copy "..\bin\$(Platform)\$(Configuration)\ConsoleHook.dll" "..\bin\x64\$(Configuration)\ConsoleHook32.dll" + + + ConsoleHook32 + + + + + X64 + + + WIN32;_WINDOWS;_USRDLL;NDEBUG;CONSOLEHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level4 + ProgramDatabase + true + + + psapi.lib;dbghelp.lib;%(AdditionalDependencies) + $(OutDir)ConsoleHook.dll + true + Windows + true + true + false + + + $(OutDir)ConsoleHook.lib + MachineX64 + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConsoleHook/ConsoleHook.vcxproj.filters b/ConsoleHook/ConsoleHook.vcxproj.filters new file mode 100644 index 00000000..b446a861 --- /dev/null +++ b/ConsoleHook/ConsoleHook.vcxproj.filters @@ -0,0 +1,59 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + + \ No newline at end of file diff --git a/ConsoleHook/stdafx.h b/ConsoleHook/stdafx.h index daf14394..baf2f2c0 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 ////////////////////////////////////////////////////////////////////////////// @@ -29,14 +29,15 @@ using namespace std; #include #include #include -#include #include -using namespace boost; #pragma warning(pop) #include "../shared/SharedMemory.h" #include "../shared/Structures.h" +#include "../shared/Cpp11Helpers.h" +#include "../shared/Win32Exception.h" + ////////////////////////////////////////////////////////////////////////////// @@ -48,9 +49,8 @@ using namespace boost; ////////////////////////////////////////////////////////////////////////////// // Version numbers -#define VERSION_MAJOR 2 -#define VERSION_MINOR 0 -#define VERSION_BUILD 146 +#include "../shared/version.h" + ////////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleWow/ConsoleWow.cpp b/ConsoleWow/ConsoleWow.cpp new file mode 100644 index 00000000..524f9983 --- /dev/null +++ b/ConsoleWow/ConsoleWow.cpp @@ -0,0 +1,12 @@ +// ConsoleWow.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" + + +int wmain(int /*argc*/, wchar_t* /*argv*/[]) +{ + UINT_PTR fnLoadLibrary = (UINT_PTR)::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); + return (int)fnLoadLibrary; +} + diff --git a/ConsoleWow/ConsoleWow.rc b/ConsoleWow/ConsoleWow.rc new file mode 100644 index 00000000..101d2830 --- /dev/null +++ b/ConsoleWow/ConsoleWow.rc @@ -0,0 +1,104 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "../shared/version.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 VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD2 + PRODUCTVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD2 + 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 "FileDescription", "Console WOW64 helper process" + VALUE "FileVersion", VERSION_FILE + VALUE "InternalName", "ConsoleZ" + VALUE "LegalCopyright", VERSION_COPYRIGHT + VALUE "LegalTrademarks", VERSION_COPYRIGHT + VALUE "OriginalFilename", "ConsoleWow.exe" + VALUE "ProductName", "ConsoleZ" + VALUE "ProductVersion", VERSION_PRODUCT + 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.vcxproj b/ConsoleWow/ConsoleWow.vcxproj new file mode 100644 index 00000000..52bca474 --- /dev/null +++ b/ConsoleWow/ConsoleWow.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug aero + Win32 + + + Debug + Win32 + + + Release aero + Win32 + + + Release + Win32 + + + + {8A25E8AF-CC4A-4145-B878-3D99271562D4} + ConsoleWow + Win32Proj + + + + Application + Unicode + true + v110 + + + Application + Unicode + true + v110 + + + Application + Unicode + v110 + + + Application + Unicode + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + ..\bin\x64\$(Configuration)\ + ..\bin\x64\$(Configuration)\ + ..\obj\x64\$(ProjectName)\$(Configuration)\ + ..\obj\x64\$(ProjectName)\$(Configuration)\ + true + true + ..\bin\x64\$(Configuration)\ + ..\bin\x64\$(Configuration)\ + ..\obj\x64\$(ProjectName)\$(Configuration)\ + ..\obj\x64\$(ProjectName)\$(Configuration)\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + false + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + false + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + false + + + C:\WinDDK\7600.16385.1\inc\atl71;C:\WinDDK\7600.16385.1\inc\mfc42;G:\gitstuff\boost_1_52_0;$(IncludePath) + false + + + + Disabled + WIN32;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + + + true + Console + MachineX86 + + + + + + + + + Disabled + WIN32;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + ProgramDatabase + true + + + + + true + Console + MachineX86 + + + + + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + Use + Level4 + ProgramDatabase + true + + + + + true + Console + true + true + MachineX86 + + + + + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + Use + Level4 + ProgramDatabase + true + + + + + true + Console + true + true + MachineX86 + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConsoleWow/ConsoleWow.vcxproj.filters b/ConsoleWow/ConsoleWow.vcxproj.filters new file mode 100644 index 00000000..c5d8be13 --- /dev/null +++ b/ConsoleWow/ConsoleWow.vcxproj.filters @@ -0,0 +1,44 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + + \ No newline at end of file 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/resource.h b/ConsoleWow/resource.h new file mode 100644 index 00000000..546c390a --- /dev/null +++ b/ConsoleWow/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ConsoleWow.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif 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..b5d3821d --- /dev/null +++ b/ConsoleWow/stdafx.h @@ -0,0 +1,21 @@ +// 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 + + +////////////////////////////////////////////////////////////////////////////// +// Version numbers + +#include "../shared/version.h" + +////////////////////////////////////////////////////////////////////////////// + diff --git a/ConsoleWow/targetver.h b/ConsoleWow/targetver.h new file mode 100644 index 00000000..7021c2a5 --- /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 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/FreeImage/FreeImage.h b/FreeImage/FreeImage.h index c9f643a8..fd2092e5 100644 --- a/FreeImage/FreeImage.h +++ b/FreeImage/FreeImage.h @@ -1,1090 +1,1104 @@ -// ========================================================== -// FreeImage 3 -// -// Design and implementation by -// - Floris van den Berg (flvdberg@wxs.nl) -// - Hervé Drolon (drolon@infonie.fr) -// -// Contributors: -// - Adam Gates (radad@xoasis.com) -// - Alex Kwak -// - Alexander Dymerets (sashad@te.net.ua) -// - Detlev Vendt (detlev.vendt@brillit.de) -// - Jan L. Nauta (jln@magentammt.com) -// - Jani Kajala (janik@remedy.fi) -// - Juergen Riecker (j.riecker@gmx.de) -// - Karl-Heinz Bussian (khbussian@moss.de) -// - Laurent Rocher (rocherl@club-internet.fr) -// - Luca Piergentili (l.pierge@terra.es) -// - Machiel ten Brinke (brinkem@uni-one.nl) -// - Markus Loibl (markus.loibl@epost.de) -// - Martin Weber (martweb@gmx.net) -// - Matthias Wandel (mwandel@rim.net) -// - Michal Novotny (michal@etc.cz) -// - Petr Pytelka (pyta@lightcomp.com) -// - Riley McNiff (rmcniff@marexgroup.com) -// - Ryan Rubley (ryan@lostreality.org) -// - Volker Gärtner (volkerg@gmx.at) -// -// This file is part of FreeImage 3 -// -// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE -// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED -// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT -// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY -// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL -// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER -// THIS DISCLAIMER. -// -// Use at your own risk! -// ========================================================== - -#ifndef FREEIMAGE_H -#define FREEIMAGE_H - -// Version information ------------------------------------------------------ - -#define FREEIMAGE_MAJOR_VERSION 3 -#define FREEIMAGE_MINOR_VERSION 13 -#define FREEIMAGE_RELEASE_SERIAL 0 - -// Compiler options --------------------------------------------------------- - -#include // needed for UNICODE functions - -#if defined(FREEIMAGE_LIB) - #define DLL_API - #define DLL_CALLCONV -#else - #if defined(_WIN32) || defined(__WIN32__) - #define DLL_CALLCONV __stdcall - // The following ifdef block is the standard way of creating macros which make exporting - // from a DLL simpler. All files within this DLL are compiled with the FREEIMAGE_EXPORTS - // symbol defined on the command line. this symbol should not be defined on any project - // that uses this DLL. This way any other project whose source files include this file see - // DLL_API functions as being imported from a DLL, wheras this DLL sees symbols - // defined with this macro as being exported. - #ifdef FREEIMAGE_EXPORTS - #define DLL_API __declspec(dllexport) - #else - #define DLL_API __declspec(dllimport) - #endif // FREEIMAGE_EXPORTS - #else - // try the gcc visibility support (see http://gcc.gnu.org/wiki/Visibility) - #if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) - #ifndef GCC_HASCLASSVISIBILITY - #define GCC_HASCLASSVISIBILITY - #endif - #endif // __GNUC__ - #define DLL_CALLCONV - #if defined(GCC_HASCLASSVISIBILITY) - #define DLL_API __attribute__ ((visibility("default"))) - #else - #define DLL_API - #endif - #endif // WIN32 / !WIN32 -#endif // FREEIMAGE_LIB - -// Some versions of gcc may have BYTE_ORDER or __BYTE_ORDER defined -// If your big endian system isn't being detected, add an OS specific check -#if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \ - (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \ - defined(__BIG_ENDIAN__) -#define FREEIMAGE_BIGENDIAN -#endif // BYTE_ORDER - -// This really only affects 24 and 32 bit formats, the rest are always RGB order. -#define FREEIMAGE_COLORORDER_BGR 0 -#define FREEIMAGE_COLORORDER_RGB 1 -#if defined(FREEIMAGE_BIGENDIAN) -#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB -#else -#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR -#endif - -// Ensure 4-byte enums if we're using Borland C++ compilers -#if defined(__BORLANDC__) -#pragma option push -b -#endif - -// For C compatibility -------------------------------------------------------- - -#ifdef __cplusplus -#define FI_DEFAULT(x) = x -#define FI_ENUM(x) enum x -#define FI_STRUCT(x) struct x -#else -#define FI_DEFAULT(x) -#define FI_ENUM(x) typedef int x; enum x -#define FI_STRUCT(x) typedef struct x x; struct x -#endif - -// Bitmap types ------------------------------------------------------------- - -FI_STRUCT (FIBITMAP) { void *data; }; -FI_STRUCT (FIMULTIBITMAP) { void *data; }; - -// Types used in the library (directly copied from Windows) ----------------- - -#if defined(__MINGW32__) && defined(_WINDOWS_H) -#define _WINDOWS_ // prevent a bug in MinGW32 -#endif // __MINGW32__ - -#ifndef _WINDOWS_ -#define _WINDOWS_ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef NULL -#define NULL 0 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -#endif - -#ifndef _MSC_VER -// define portable types for 32-bit / 64-bit OS -#include -typedef int32_t BOOL; -typedef uint8_t BYTE; -typedef uint16_t WORD; -typedef uint32_t DWORD; -typedef int32_t LONG; -#else -// MS is not C99 ISO compliant -typedef long BOOL; -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; -typedef long LONG; -#endif // _MSC_VER - -#if (defined(_WIN32) || defined(__WIN32__)) -#pragma pack(push, 1) -#else -#pragma pack(1) -#endif // WIN32 - -typedef struct tagRGBQUAD { -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; -#else - BYTE rgbRed; - BYTE rgbGreen; - BYTE rgbBlue; -#endif // FREEIMAGE_COLORORDER - BYTE rgbReserved; -} RGBQUAD; - -typedef struct tagRGBTRIPLE { -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR - BYTE rgbtBlue; - BYTE rgbtGreen; - BYTE rgbtRed; -#else - BYTE rgbtRed; - BYTE rgbtGreen; - BYTE rgbtBlue; -#endif // FREEIMAGE_COLORORDER -} RGBTRIPLE; - -#if (defined(_WIN32) || defined(__WIN32__)) -#pragma pack(pop) -#else -#pragma pack() -#endif // WIN32 - -typedef struct tagBITMAPINFOHEADER{ - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; -} BITMAPINFOHEADER, *PBITMAPINFOHEADER; - -typedef struct tagBITMAPINFO { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; -} BITMAPINFO, *PBITMAPINFO; - -#endif // _WINDOWS_ - -// Types used in the library (specific to FreeImage) ------------------------ - -#if (defined(_WIN32) || defined(__WIN32__)) -#pragma pack(push, 1) -#else -#pragma pack(1) -#endif // WIN32 - -/** 48-bit RGB -*/ -typedef struct tagFIRGB16 { - WORD red; - WORD green; - WORD blue; -} FIRGB16; - -/** 64-bit RGBA -*/ -typedef struct tagFIRGBA16 { - WORD red; - WORD green; - WORD blue; - WORD alpha; -} FIRGBA16; - -/** 96-bit RGB Float -*/ -typedef struct tagFIRGBF { - float red; - float green; - float blue; -} FIRGBF; - -/** 128-bit RGBA Float -*/ -typedef struct tagFIRGBAF { - float red; - float green; - float blue; - float alpha; -} FIRGBAF; - -/** Data structure for COMPLEX type (complex number) -*/ -typedef struct tagFICOMPLEX { - /// real part - double r; - /// imaginary part - double i; -} FICOMPLEX; - -#if (defined(_WIN32) || defined(__WIN32__)) -#pragma pack(pop) -#else -#pragma pack() -#endif // WIN32 - -// Indexes for byte arrays, masks and shifts for treating pixels as words --- -// These coincide with the order of RGBQUAD and RGBTRIPLE ------------------- - -#ifndef FREEIMAGE_BIGENDIAN -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR -// Little Endian (x86 / MS Windows, Linux) : BGR(A) order -#define FI_RGBA_RED 2 -#define FI_RGBA_GREEN 1 -#define FI_RGBA_BLUE 0 -#define FI_RGBA_ALPHA 3 -#define FI_RGBA_RED_MASK 0x00FF0000 -#define FI_RGBA_GREEN_MASK 0x0000FF00 -#define FI_RGBA_BLUE_MASK 0x000000FF -#define FI_RGBA_ALPHA_MASK 0xFF000000 -#define FI_RGBA_RED_SHIFT 16 -#define FI_RGBA_GREEN_SHIFT 8 -#define FI_RGBA_BLUE_SHIFT 0 -#define FI_RGBA_ALPHA_SHIFT 24 -#else -// Little Endian (x86 / MaxOSX) : RGB(A) order -#define FI_RGBA_RED 0 -#define FI_RGBA_GREEN 1 -#define FI_RGBA_BLUE 2 -#define FI_RGBA_ALPHA 3 -#define FI_RGBA_RED_MASK 0x000000FF -#define FI_RGBA_GREEN_MASK 0x0000FF00 -#define FI_RGBA_BLUE_MASK 0x00FF0000 -#define FI_RGBA_ALPHA_MASK 0xFF000000 -#define FI_RGBA_RED_SHIFT 0 -#define FI_RGBA_GREEN_SHIFT 8 -#define FI_RGBA_BLUE_SHIFT 16 -#define FI_RGBA_ALPHA_SHIFT 24 -#endif // FREEIMAGE_COLORORDER -#else -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR -// Big Endian (PPC / none) : BGR(A) order -#define FI_RGBA_RED 2 -#define FI_RGBA_GREEN 1 -#define FI_RGBA_BLUE 0 -#define FI_RGBA_ALPHA 3 -#define FI_RGBA_RED_MASK 0x0000FF00 -#define FI_RGBA_GREEN_MASK 0x00FF0000 -#define FI_RGBA_BLUE_MASK 0xFF000000 -#define FI_RGBA_ALPHA_MASK 0x000000FF -#define FI_RGBA_RED_SHIFT 8 -#define FI_RGBA_GREEN_SHIFT 16 -#define FI_RGBA_BLUE_SHIFT 24 -#define FI_RGBA_ALPHA_SHIFT 0 -#else -// Big Endian (PPC / Linux, MaxOSX) : RGB(A) order -#define FI_RGBA_RED 0 -#define FI_RGBA_GREEN 1 -#define FI_RGBA_BLUE 2 -#define FI_RGBA_ALPHA 3 -#define FI_RGBA_RED_MASK 0xFF000000 -#define FI_RGBA_GREEN_MASK 0x00FF0000 -#define FI_RGBA_BLUE_MASK 0x0000FF00 -#define FI_RGBA_ALPHA_MASK 0x000000FF -#define FI_RGBA_RED_SHIFT 24 -#define FI_RGBA_GREEN_SHIFT 16 -#define FI_RGBA_BLUE_SHIFT 8 -#define FI_RGBA_ALPHA_SHIFT 0 -#endif // FREEIMAGE_COLORORDER -#endif // FREEIMAGE_BIGENDIAN - -#define FI_RGBA_RGB_MASK (FI_RGBA_RED_MASK|FI_RGBA_GREEN_MASK|FI_RGBA_BLUE_MASK) - -// The 16bit macros only include masks and shifts, since each color element is not byte aligned - -#define FI16_555_RED_MASK 0x7C00 -#define FI16_555_GREEN_MASK 0x03E0 -#define FI16_555_BLUE_MASK 0x001F -#define FI16_555_RED_SHIFT 10 -#define FI16_555_GREEN_SHIFT 5 -#define FI16_555_BLUE_SHIFT 0 -#define FI16_565_RED_MASK 0xF800 -#define FI16_565_GREEN_MASK 0x07E0 -#define FI16_565_BLUE_MASK 0x001F -#define FI16_565_RED_SHIFT 11 -#define FI16_565_GREEN_SHIFT 5 -#define FI16_565_BLUE_SHIFT 0 - -// ICC profile support ------------------------------------------------------ - -#define FIICC_DEFAULT 0x00 -#define FIICC_COLOR_IS_CMYK 0x01 - -FI_STRUCT (FIICCPROFILE) { - WORD flags; // info flag - DWORD size; // profile's size measured in bytes - void *data; // points to a block of contiguous memory containing the profile -}; - -// Important enums ---------------------------------------------------------- - -/** I/O image format identifiers. -*/ -FI_ENUM(FREE_IMAGE_FORMAT) { - FIF_UNKNOWN = -1, - FIF_BMP = 0, - FIF_ICO = 1, - FIF_JPEG = 2, - FIF_JNG = 3, - FIF_KOALA = 4, - FIF_LBM = 5, - FIF_IFF = FIF_LBM, - FIF_MNG = 6, - FIF_PBM = 7, - FIF_PBMRAW = 8, - FIF_PCD = 9, - FIF_PCX = 10, - FIF_PGM = 11, - FIF_PGMRAW = 12, - FIF_PNG = 13, - FIF_PPM = 14, - FIF_PPMRAW = 15, - FIF_RAS = 16, - FIF_TARGA = 17, - FIF_TIFF = 18, - FIF_WBMP = 19, - FIF_PSD = 20, - FIF_CUT = 21, - FIF_XBM = 22, - FIF_XPM = 23, - FIF_DDS = 24, - FIF_GIF = 25, - FIF_HDR = 26, - FIF_FAXG3 = 27, - FIF_SGI = 28, - FIF_EXR = 29, - FIF_J2K = 30, - FIF_JP2 = 31, - FIF_PFM = 32, - FIF_PICT = 33, - FIF_RAW = 34 -}; - -/** Image type used in FreeImage. -*/ -FI_ENUM(FREE_IMAGE_TYPE) { - FIT_UNKNOWN = 0, // unknown type - FIT_BITMAP = 1, // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit - FIT_UINT16 = 2, // array of unsigned short : unsigned 16-bit - FIT_INT16 = 3, // array of short : signed 16-bit - FIT_UINT32 = 4, // array of unsigned long : unsigned 32-bit - FIT_INT32 = 5, // array of long : signed 32-bit - FIT_FLOAT = 6, // array of float : 32-bit IEEE floating point - FIT_DOUBLE = 7, // array of double : 64-bit IEEE floating point - FIT_COMPLEX = 8, // array of FICOMPLEX : 2 x 64-bit IEEE floating point - FIT_RGB16 = 9, // 48-bit RGB image : 3 x 16-bit - FIT_RGBA16 = 10, // 64-bit RGBA image : 4 x 16-bit - FIT_RGBF = 11, // 96-bit RGB float image : 3 x 32-bit IEEE floating point - FIT_RGBAF = 12 // 128-bit RGBA float image : 4 x 32-bit IEEE floating point -}; - -/** Image color type used in FreeImage. -*/ -FI_ENUM(FREE_IMAGE_COLOR_TYPE) { - FIC_MINISWHITE = 0, // min value is white - FIC_MINISBLACK = 1, // min value is black - FIC_RGB = 2, // RGB color model - FIC_PALETTE = 3, // color map indexed - FIC_RGBALPHA = 4, // RGB color model with alpha channel - FIC_CMYK = 5 // CMYK color model -}; - -/** Color quantization algorithms. -Constants used in FreeImage_ColorQuantize. -*/ -FI_ENUM(FREE_IMAGE_QUANTIZE) { - FIQ_WUQUANT = 0, // Xiaolin Wu color quantization algorithm - FIQ_NNQUANT = 1 // NeuQuant neural-net quantization algorithm by Anthony Dekker -}; - -/** Dithering algorithms. -Constants used in FreeImage_Dither. -*/ -FI_ENUM(FREE_IMAGE_DITHER) { - FID_FS = 0, // Floyd & Steinberg error diffusion - FID_BAYER4x4 = 1, // Bayer ordered dispersed dot dithering (order 2 dithering matrix) - FID_BAYER8x8 = 2, // Bayer ordered dispersed dot dithering (order 3 dithering matrix) - FID_CLUSTER6x6 = 3, // Ordered clustered dot dithering (order 3 - 6x6 matrix) - FID_CLUSTER8x8 = 4, // Ordered clustered dot dithering (order 4 - 8x8 matrix) - FID_CLUSTER16x16= 5, // Ordered clustered dot dithering (order 8 - 16x16 matrix) - FID_BAYER16x16 = 6 // Bayer ordered dispersed dot dithering (order 4 dithering matrix) -}; - -/** Lossless JPEG transformations -Constants used in FreeImage_JPEGTransform -*/ -FI_ENUM(FREE_IMAGE_JPEG_OPERATION) { - FIJPEG_OP_NONE = 0, // no transformation - FIJPEG_OP_FLIP_H = 1, // horizontal flip - FIJPEG_OP_FLIP_V = 2, // vertical flip - FIJPEG_OP_TRANSPOSE = 3, // transpose across UL-to-LR axis - FIJPEG_OP_TRANSVERSE = 4, // transpose across UR-to-LL axis - FIJPEG_OP_ROTATE_90 = 5, // 90-degree clockwise rotation - FIJPEG_OP_ROTATE_180 = 6, // 180-degree rotation - FIJPEG_OP_ROTATE_270 = 7 // 270-degree clockwise (or 90 ccw) -}; - -/** Tone mapping operators. -Constants used in FreeImage_ToneMapping. -*/ -FI_ENUM(FREE_IMAGE_TMO) { - FITMO_DRAGO03 = 0, // Adaptive logarithmic mapping (F. Drago, 2003) - FITMO_REINHARD05 = 1, // Dynamic range reduction inspired by photoreceptor physiology (E. Reinhard, 2005) - FITMO_FATTAL02 = 2 // Gradient domain high dynamic range compression (R. Fattal, 2002) -}; - -/** Upsampling / downsampling filters. -Constants used in FreeImage_Rescale. -*/ -FI_ENUM(FREE_IMAGE_FILTER) { - FILTER_BOX = 0, // Box, pulse, Fourier window, 1st order (constant) b-spline - FILTER_BICUBIC = 1, // Mitchell & Netravali's two-param cubic filter - FILTER_BILINEAR = 2, // Bilinear filter - FILTER_BSPLINE = 3, // 4th order (cubic) b-spline - FILTER_CATMULLROM = 4, // Catmull-Rom spline, Overhauser spline - FILTER_LANCZOS3 = 5 // Lanczos3 filter -}; - -/** Color channels. -Constants used in color manipulation routines. -*/ -FI_ENUM(FREE_IMAGE_COLOR_CHANNEL) { - FICC_RGB = 0, // Use red, green and blue channels - FICC_RED = 1, // Use red channel - FICC_GREEN = 2, // Use green channel - FICC_BLUE = 3, // Use blue channel - FICC_ALPHA = 4, // Use alpha channel - FICC_BLACK = 5, // Use black channel - FICC_REAL = 6, // Complex images: use real part - FICC_IMAG = 7, // Complex images: use imaginary part - FICC_MAG = 8, // Complex images: use magnitude - FICC_PHASE = 9 // Complex images: use phase -}; - -// Metadata support --------------------------------------------------------- - -/** - Tag data type information (based on TIFF specifications) - - Note: RATIONALs are the ratio of two 32-bit integer values. -*/ -FI_ENUM(FREE_IMAGE_MDTYPE) { - FIDT_NOTYPE = 0, // placeholder - FIDT_BYTE = 1, // 8-bit unsigned integer - FIDT_ASCII = 2, // 8-bit bytes w/ last byte null - FIDT_SHORT = 3, // 16-bit unsigned integer - FIDT_LONG = 4, // 32-bit unsigned integer - FIDT_RATIONAL = 5, // 64-bit unsigned fraction - FIDT_SBYTE = 6, // 8-bit signed integer - FIDT_UNDEFINED = 7, // 8-bit untyped data - FIDT_SSHORT = 8, // 16-bit signed integer - FIDT_SLONG = 9, // 32-bit signed integer - FIDT_SRATIONAL = 10, // 64-bit signed fraction - FIDT_FLOAT = 11, // 32-bit IEEE floating point - FIDT_DOUBLE = 12, // 64-bit IEEE floating point - FIDT_IFD = 13, // 32-bit unsigned integer (offset) - FIDT_PALETTE = 14 // 32-bit RGBQUAD -}; - -/** - Metadata models supported by FreeImage -*/ -FI_ENUM(FREE_IMAGE_MDMODEL) { - FIMD_NODATA = -1, - FIMD_COMMENTS = 0, // single comment or keywords - FIMD_EXIF_MAIN = 1, // Exif-TIFF metadata - FIMD_EXIF_EXIF = 2, // Exif-specific metadata - FIMD_EXIF_GPS = 3, // Exif GPS metadata - FIMD_EXIF_MAKERNOTE = 4, // Exif maker note metadata - FIMD_EXIF_INTEROP = 5, // Exif interoperability metadata - FIMD_IPTC = 6, // IPTC/NAA metadata - FIMD_XMP = 7, // Abobe XMP metadata - FIMD_GEOTIFF = 8, // GeoTIFF metadata - FIMD_ANIMATION = 9, // Animation metadata - FIMD_CUSTOM = 10 // Used to attach other metadata types to a dib -}; - -/** - Handle to a metadata model -*/ -FI_STRUCT (FIMETADATA) { void *data; }; - -/** - Handle to a FreeImage tag -*/ -FI_STRUCT (FITAG) { void *data; }; - -// File IO routines --------------------------------------------------------- - -#ifndef FREEIMAGE_IO -#define FREEIMAGE_IO - -typedef void* fi_handle; -typedef unsigned (DLL_CALLCONV *FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); -typedef unsigned (DLL_CALLCONV *FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); -typedef int (DLL_CALLCONV *FI_SeekProc) (fi_handle handle, long offset, int origin); -typedef long (DLL_CALLCONV *FI_TellProc) (fi_handle handle); - -#if (defined(_WIN32) || defined(__WIN32__)) -#pragma pack(push, 1) -#else -#pragma pack(1) -#endif // WIN32 - -FI_STRUCT(FreeImageIO) { - FI_ReadProc read_proc; // pointer to the function used to read data - FI_WriteProc write_proc; // pointer to the function used to write data - FI_SeekProc seek_proc; // pointer to the function used to seek - FI_TellProc tell_proc; // pointer to the function used to aquire the current position -}; - -#if (defined(_WIN32) || defined(__WIN32__)) -#pragma pack(pop) -#else -#pragma pack() -#endif // WIN32 - -/** -Handle to a memory I/O stream -*/ -FI_STRUCT (FIMEMORY) { void *data; }; - -#endif // FREEIMAGE_IO - -// Plugin routines ---------------------------------------------------------- - -#ifndef PLUGINS -#define PLUGINS - -typedef const char *(DLL_CALLCONV *FI_FormatProc)(void); -typedef const char *(DLL_CALLCONV *FI_DescriptionProc)(void); -typedef const char *(DLL_CALLCONV *FI_ExtensionListProc)(void); -typedef const char *(DLL_CALLCONV *FI_RegExprProc)(void); -typedef void *(DLL_CALLCONV *FI_OpenProc)(FreeImageIO *io, fi_handle handle, BOOL read); -typedef void (DLL_CALLCONV *FI_CloseProc)(FreeImageIO *io, fi_handle handle, void *data); -typedef int (DLL_CALLCONV *FI_PageCountProc)(FreeImageIO *io, fi_handle handle, void *data); -typedef int (DLL_CALLCONV *FI_PageCapabilityProc)(FreeImageIO *io, fi_handle handle, void *data); -typedef FIBITMAP *(DLL_CALLCONV *FI_LoadProc)(FreeImageIO *io, fi_handle handle, int page, int flags, void *data); -typedef BOOL (DLL_CALLCONV *FI_SaveProc)(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data); -typedef BOOL (DLL_CALLCONV *FI_ValidateProc)(FreeImageIO *io, fi_handle handle); -typedef const char *(DLL_CALLCONV *FI_MimeProc)(void); -typedef BOOL (DLL_CALLCONV *FI_SupportsExportBPPProc)(int bpp); -typedef BOOL (DLL_CALLCONV *FI_SupportsExportTypeProc)(FREE_IMAGE_TYPE type); -typedef BOOL (DLL_CALLCONV *FI_SupportsICCProfilesProc)(void); - -FI_STRUCT (Plugin) { - FI_FormatProc format_proc; - FI_DescriptionProc description_proc; - FI_ExtensionListProc extension_proc; - FI_RegExprProc regexpr_proc; - FI_OpenProc open_proc; - FI_CloseProc close_proc; - FI_PageCountProc pagecount_proc; - FI_PageCapabilityProc pagecapability_proc; - FI_LoadProc load_proc; - FI_SaveProc save_proc; - FI_ValidateProc validate_proc; - FI_MimeProc mime_proc; - FI_SupportsExportBPPProc supports_export_bpp_proc; - FI_SupportsExportTypeProc supports_export_type_proc; - FI_SupportsICCProfilesProc supports_icc_profiles_proc; -}; - -typedef void (DLL_CALLCONV *FI_InitProc)(Plugin *plugin, int format_id); - -#endif // PLUGINS - - -// Load / Save flag constants ----------------------------------------------- - -#define BMP_DEFAULT 0 -#define BMP_SAVE_RLE 1 -#define CUT_DEFAULT 0 -#define DDS_DEFAULT 0 -#define EXR_DEFAULT 0 // save data as half with piz-based wavelet compression -#define EXR_FLOAT 0x0001 // save data as float instead of as half (not recommended) -#define EXR_NONE 0x0002 // save with no compression -#define EXR_ZIP 0x0004 // save with zlib compression, in blocks of 16 scan lines -#define EXR_PIZ 0x0008 // save with piz-based wavelet compression -#define EXR_PXR24 0x0010 // save with lossy 24-bit float compression -#define EXR_B44 0x0020 // save with lossy 44% float compression - goes to 22% when combined with EXR_LC -#define EXR_LC 0x0040 // save images with one luminance and two chroma channels, rather than as RGB (lossy compression) -#define FAXG3_DEFAULT 0 -#define GIF_DEFAULT 0 -#define GIF_LOAD256 1 // Load the image as a 256 color image with ununsed palette entries, if it's 16 or 2 color -#define GIF_PLAYBACK 2 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading -#define HDR_DEFAULT 0 -#define ICO_DEFAULT 0 -#define ICO_MAKEALPHA 1 // convert to 32bpp and create an alpha channel from the AND-mask when loading -#define IFF_DEFAULT 0 -#define J2K_DEFAULT 0 // save with a 16:1 rate -#define JP2_DEFAULT 0 // save with a 16:1 rate -#define JPEG_DEFAULT 0 // loading (see JPEG_FAST); saving (see JPEG_QUALITYGOOD|JPEG_SUBSAMPLING_420) -#define JPEG_FAST 0x0001 // load the file as fast as possible, sacrificing some quality -#define JPEG_ACCURATE 0x0002 // load the file with the best quality, sacrificing some speed -#define JPEG_CMYK 0x0004 // load separated CMYK "as is" (use | to combine with other load flags) -#define JPEG_EXIFROTATE 0x0008 // load and rotate according to Exif 'Orientation' tag if available -#define JPEG_QUALITYSUPERB 0x80 // save with superb quality (100:1) -#define JPEG_QUALITYGOOD 0x0100 // save with good quality (75:1) -#define JPEG_QUALITYNORMAL 0x0200 // save with normal quality (50:1) -#define JPEG_QUALITYAVERAGE 0x0400 // save with average quality (25:1) -#define JPEG_QUALITYBAD 0x0800 // save with bad quality (10:1) -#define JPEG_PROGRESSIVE 0x2000 // save as a progressive-JPEG (use | to combine with other save flags) -#define JPEG_SUBSAMPLING_411 0x1000 // save with high 4x1 chroma subsampling (4:1:1) -#define JPEG_SUBSAMPLING_420 0x4000 // save with medium 2x2 medium chroma subsampling (4:2:0) - default value -#define JPEG_SUBSAMPLING_422 0x8000 // save with low 2x1 chroma subsampling (4:2:2) -#define JPEG_SUBSAMPLING_444 0x10000 // save with no chroma subsampling (4:4:4) -#define KOALA_DEFAULT 0 -#define LBM_DEFAULT 0 -#define MNG_DEFAULT 0 -#define PCD_DEFAULT 0 -#define PCD_BASE 1 // load the bitmap sized 768 x 512 -#define PCD_BASEDIV4 2 // load the bitmap sized 384 x 256 -#define PCD_BASEDIV16 3 // load the bitmap sized 192 x 128 -#define PCX_DEFAULT 0 -#define PFM_DEFAULT 0 -#define PICT_DEFAULT 0 -#define PNG_DEFAULT 0 -#define PNG_IGNOREGAMMA 1 // loading: avoid gamma correction -#define PNG_Z_BEST_SPEED 0x0001 // save using ZLib level 1 compression flag (default value is 6) -#define PNG_Z_DEFAULT_COMPRESSION 0x0006 // save using ZLib level 6 compression flag (default recommended value) -#define PNG_Z_BEST_COMPRESSION 0x0009 // save using ZLib level 9 compression flag (default value is 6) -#define PNG_Z_NO_COMPRESSION 0x0100 // save without ZLib compression -#define PNG_INTERLACED 0x0200 // save using Adam7 interlacing (use | to combine with other save flags) -#define PNM_DEFAULT 0 -#define PNM_SAVE_RAW 0 // If set the writer saves in RAW format (i.e. P4, P5 or P6) -#define PNM_SAVE_ASCII 1 // If set the writer saves in ASCII format (i.e. P1, P2 or P3) -#define PSD_DEFAULT 0 -#define RAS_DEFAULT 0 -#define RAW_DEFAULT 0 // load the file as linear RGB 48-bit -#define RAW_PREVIEW 1 // try to load the embedded JPEG preview with included Exif Data or default to RGB 24-bit -#define RAW_DISPLAY 2 // load the file as RGB 24-bit -#define SGI_DEFAULT 0 -#define TARGA_DEFAULT 0 -#define TARGA_LOAD_RGB888 1 // If set the loader converts RGB555 and ARGB8888 -> RGB888. -#define TIFF_DEFAULT 0 -#define TIFF_CMYK 0x0001 // reads/stores tags for separated CMYK (use | to combine with compression flags) -#define TIFF_PACKBITS 0x0100 // save using PACKBITS compression -#define TIFF_DEFLATE 0x0200 // save using DEFLATE compression (a.k.a. ZLIB compression) -#define TIFF_ADOBE_DEFLATE 0x0400 // save using ADOBE DEFLATE compression -#define TIFF_NONE 0x0800 // save without any compression -#define TIFF_CCITTFAX3 0x1000 // save using CCITT Group 3 fax encoding -#define TIFF_CCITTFAX4 0x2000 // save using CCITT Group 4 fax encoding -#define TIFF_LZW 0x4000 // save using LZW compression -#define TIFF_JPEG 0x8000 // save using JPEG compression -#define WBMP_DEFAULT 0 -#define XBM_DEFAULT 0 -#define XPM_DEFAULT 0 - -// Background filling options --------------------------------------------------------- -// Constants used in FreeImage_FillBackground and FreeImage_EnlargeCanvas - -#define FI_COLOR_IS_RGB_COLOR 0x00 // RGBQUAD color is a RGB color (contains no valid alpha channel) -#define FI_COLOR_IS_RGBA_COLOR 0x01 // RGBQUAD color is a RGBA color (contains a valid alpha channel) -#define FI_COLOR_FIND_EQUAL_COLOR 0x02 // For palettized images: lookup equal RGB color from palette -#define FI_COLOR_ALPHA_IS_INDEX 0x04 // The color's rgbReserved member (alpha) contains the palette index to be used -#define FI_COLOR_PALETTE_SEARCH_MASK (FI_COLOR_FIND_EQUAL_COLOR | FI_COLOR_ALPHA_IS_INDEX) // No color lookup is performed - - -#ifdef __cplusplus -extern "C" { -#endif - -// Init / Error routines ---------------------------------------------------- - -DLL_API void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only FI_DEFAULT(FALSE)); -DLL_API void DLL_CALLCONV FreeImage_DeInitialise(void); - -// Version routines --------------------------------------------------------- - -DLL_API const char *DLL_CALLCONV FreeImage_GetVersion(void); -DLL_API const char *DLL_CALLCONV FreeImage_GetCopyrightMessage(void); - -// Message output functions ------------------------------------------------- - -typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg); -typedef void (DLL_CALLCONV *FreeImage_OutputMessageFunctionStdCall)(FREE_IMAGE_FORMAT fif, const char *msg); - -DLL_API void DLL_CALLCONV FreeImage_SetOutputMessageStdCall(FreeImage_OutputMessageFunctionStdCall omf); -DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf); -DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt, ...); - -// Allocate / Clone / Unload routines --------------------------------------- - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp FI_DEFAULT(8), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); -DLL_API FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib); -DLL_API void DLL_CALLCONV FreeImage_Unload(FIBITMAP *dib); - -// Load / Save routines ----------------------------------------------------- - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, int flags FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); -DLL_API BOOL DLL_CALLCONV FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); -DLL_API BOOL DLL_CALLCONV FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags FI_DEFAULT(0)); -DLL_API BOOL DLL_CALLCONV FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); - -// Memory I/O stream routines ----------------------------------------------- - -DLL_API FIMEMORY *DLL_CALLCONV FreeImage_OpenMemory(BYTE *data FI_DEFAULT(0), DWORD size_in_bytes FI_DEFAULT(0)); -DLL_API void DLL_CALLCONV FreeImage_CloseMemory(FIMEMORY *stream); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); -DLL_API BOOL DLL_CALLCONV FreeImage_SaveToMemory(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FIMEMORY *stream, int flags FI_DEFAULT(0)); -DLL_API long DLL_CALLCONV FreeImage_TellMemory(FIMEMORY *stream); -DLL_API BOOL DLL_CALLCONV FreeImage_SeekMemory(FIMEMORY *stream, long offset, int origin); -DLL_API BOOL DLL_CALLCONV FreeImage_AcquireMemory(FIMEMORY *stream, BYTE **data, DWORD *size_in_bytes); -DLL_API unsigned DLL_CALLCONV FreeImage_ReadMemory(void *buffer, unsigned size, unsigned count, FIMEMORY *stream); -DLL_API unsigned DLL_CALLCONV FreeImage_WriteMemory(const void *buffer, unsigned size, unsigned count, FIMEMORY *stream); -DLL_API FIMULTIBITMAP *DLL_CALLCONV FreeImage_LoadMultiBitmapFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); - -// Plugin Interface --------------------------------------------------------- - -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterExternalPlugin(const char *path, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); -DLL_API int DLL_CALLCONV FreeImage_GetFIFCount(void); -DLL_API int DLL_CALLCONV FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable); -DLL_API int DLL_CALLCONV FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFormat(const char *format); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromMime(const char *mime); -DLL_API const char *DLL_CALLCONV FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); -DLL_API const char *DLL_CALLCONV FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); -DLL_API const char *DLL_CALLCONV FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif); -DLL_API const char *DLL_CALLCONV FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif); -DLL_API const char *DLL_CALLCONV FreeImage_GetFIFMimeType(FREE_IMAGE_FORMAT fif); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilename(const char *filename); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilenameU(const wchar_t *filename); -DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif); -DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); -DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportBPP(FREE_IMAGE_FORMAT fif, int bpp); -DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportType(FREE_IMAGE_FORMAT fif, FREE_IMAGE_TYPE type); -DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsICCProfiles(FREE_IMAGE_FORMAT fif); - -// Multipaging interface ---------------------------------------------------- - -DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory FI_DEFAULT(FALSE), int flags FI_DEFAULT(0)); -DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); -DLL_API BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags FI_DEFAULT(0)); -DLL_API int DLL_CALLCONV FreeImage_GetPageCount(FIMULTIBITMAP *bitmap); -DLL_API void DLL_CALLCONV FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data); -DLL_API void DLL_CALLCONV FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data); -DLL_API void DLL_CALLCONV FreeImage_DeletePage(FIMULTIBITMAP *bitmap, int page); -DLL_API FIBITMAP * DLL_CALLCONV FreeImage_LockPage(FIMULTIBITMAP *bitmap, int page); -DLL_API void DLL_CALLCONV FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *data, BOOL changed); -DLL_API BOOL DLL_CALLCONV FreeImage_MovePage(FIMULTIBITMAP *bitmap, int target, int source); -DLL_API BOOL DLL_CALLCONV FreeImage_GetLockedPageNumbers(FIMULTIBITMAP *bitmap, int *pages, int *count); - -// Filetype request routines ------------------------------------------------ - -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileType(const char *filename, int size FI_DEFAULT(0)); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeU(const wchar_t *filename, int size FI_DEFAULT(0)); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size FI_DEFAULT(0)); -DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromMemory(FIMEMORY *stream, int size FI_DEFAULT(0)); - -// Image type request routine ----------------------------------------------- - -DLL_API FREE_IMAGE_TYPE DLL_CALLCONV FreeImage_GetImageType(FIBITMAP *dib); - -// FreeImage helper routines ------------------------------------------------ - -DLL_API BOOL DLL_CALLCONV FreeImage_IsLittleEndian(void); -DLL_API BOOL DLL_CALLCONV FreeImage_LookupX11Color(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); -DLL_API BOOL DLL_CALLCONV FreeImage_LookupSVGColor(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); - -// Pixel access routines ---------------------------------------------------- - -DLL_API BYTE *DLL_CALLCONV FreeImage_GetBits(FIBITMAP *dib); -DLL_API BYTE *DLL_CALLCONV FreeImage_GetScanLine(FIBITMAP *dib, int scanline); - -DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); -DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); -DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); -DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); - -// DIB info routines -------------------------------------------------------- - -DLL_API unsigned DLL_CALLCONV FreeImage_GetColorsUsed(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetBPP(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetWidth(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetHeight(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetLine(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib); -DLL_API RGBQUAD *DLL_CALLCONV FreeImage_GetPalette(FIBITMAP *dib); - -DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterX(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterY(FIBITMAP *dib); -DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res); -DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res); - -DLL_API BITMAPINFOHEADER *DLL_CALLCONV FreeImage_GetInfoHeader(FIBITMAP *dib); -DLL_API BITMAPINFO *DLL_CALLCONV FreeImage_GetInfo(FIBITMAP *dib); -DLL_API FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib); - -DLL_API unsigned DLL_CALLCONV FreeImage_GetRedMask(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetGreenMask(FIBITMAP *dib); -DLL_API unsigned DLL_CALLCONV FreeImage_GetBlueMask(FIBITMAP *dib); - -DLL_API unsigned DLL_CALLCONV FreeImage_GetTransparencyCount(FIBITMAP *dib); -DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib); -DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled); -DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count); -DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib); -DLL_API void DLL_CALLCONV FreeImage_SetTransparentIndex(FIBITMAP *dib, int index); -DLL_API int DLL_CALLCONV FreeImage_GetTransparentIndex(FIBITMAP *dib); - -DLL_API BOOL DLL_CALLCONV FreeImage_HasBackgroundColor(FIBITMAP *dib); -DLL_API BOOL DLL_CALLCONV FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); -DLL_API BOOL DLL_CALLCONV FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); - - -// ICC profile routines ----------------------------------------------------- - -DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_GetICCProfile(FIBITMAP *dib); -DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size); -DLL_API void DLL_CALLCONV FreeImage_DestroyICCProfile(FIBITMAP *dib); - -// Line conversion routines ------------------------------------------------- - -DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To4(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To4(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To4(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To4(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels); -DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels); - -// Smart conversion routines ------------------------------------------------ - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo4Bits(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo8Bits(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToGreyscale(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits555(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits565(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo24Bits(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo32Bits(FIBITMAP *dib); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize FI_DEFAULT(FIQ_WUQUANT), int PaletteSize FI_DEFAULT(256), int ReserveSize FI_DEFAULT(0), RGBQUAD *ReservePalette FI_DEFAULT(NULL)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Threshold(FIBITMAP *dib, BYTE T); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Dither(FIBITMAP *dib, FREE_IMAGE_DITHER algorithm); - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); -DLL_API void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib); - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToStandardType(FIBITMAP *src, BOOL scale_linear FI_DEFAULT(TRUE)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear FI_DEFAULT(TRUE)); - -// tone mapping operators -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ToneMapping(FIBITMAP *dib, FREE_IMAGE_TMO tmo, double first_param FI_DEFAULT(0), double second_param FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoDrago03(FIBITMAP *src, double gamma FI_DEFAULT(2.2), double exposure FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0), double adaptation FI_DEFAULT(1), double color_correction FI_DEFAULT(0)); - -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoFattal02(FIBITMAP *src, double color_saturation FI_DEFAULT(0.5), double attenuation FI_DEFAULT(0.85)); - -// ZLib interface ----------------------------------------------------------- - -DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); -DLL_API DWORD DLL_CALLCONV FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); -DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); -DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); -DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size); - -// -------------------------------------------------------------------------- -// Metadata routines -------------------------------------------------------- -// -------------------------------------------------------------------------- - -// tag creation / destruction -DLL_API FITAG *DLL_CALLCONV FreeImage_CreateTag(void); -DLL_API void DLL_CALLCONV FreeImage_DeleteTag(FITAG *tag); -DLL_API FITAG *DLL_CALLCONV FreeImage_CloneTag(FITAG *tag); - -// tag getters and setters -DLL_API const char *DLL_CALLCONV FreeImage_GetTagKey(FITAG *tag); -DLL_API const char *DLL_CALLCONV FreeImage_GetTagDescription(FITAG *tag); -DLL_API WORD DLL_CALLCONV FreeImage_GetTagID(FITAG *tag); -DLL_API FREE_IMAGE_MDTYPE DLL_CALLCONV FreeImage_GetTagType(FITAG *tag); -DLL_API DWORD DLL_CALLCONV FreeImage_GetTagCount(FITAG *tag); -DLL_API DWORD DLL_CALLCONV FreeImage_GetTagLength(FITAG *tag); -DLL_API const void *DLL_CALLCONV FreeImage_GetTagValue(FITAG *tag); - -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagKey(FITAG *tag, const char *key); -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagDescription(FITAG *tag, const char *description); -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagID(FITAG *tag, WORD id); -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type); -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagCount(FITAG *tag, DWORD count); -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagLength(FITAG *tag, DWORD length); -DLL_API BOOL DLL_CALLCONV FreeImage_SetTagValue(FITAG *tag, const void *value); - -// iterator -DLL_API FIMETADATA *DLL_CALLCONV FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag); -DLL_API BOOL DLL_CALLCONV FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag); -DLL_API void DLL_CALLCONV FreeImage_FindCloseMetadata(FIMETADATA *mdhandle); - -// metadata setter and getter -DLL_API BOOL DLL_CALLCONV FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag); -DLL_API BOOL DLL_CALLCONV FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag); - -// helpers -DLL_API unsigned DLL_CALLCONV FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib); -DLL_API BOOL DLL_CALLCONV FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src); - -// tag to C string conversion -DLL_API const char* DLL_CALLCONV FreeImage_TagToString(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make FI_DEFAULT(NULL)); - -// -------------------------------------------------------------------------- -// Image manipulation toolkit ----------------------------------------------- -// -------------------------------------------------------------------------- - -// rotation and flipping -/// @deprecated see FreeImage_Rotate -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateClassic(FIBITMAP *dib, double angle); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor FI_DEFAULT(NULL)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask); -DLL_API BOOL DLL_CALLCONV FreeImage_FlipHorizontal(FIBITMAP *dib); -DLL_API BOOL DLL_CALLCONV FreeImage_FlipVertical(FIBITMAP *dib); -DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(FALSE)); -DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(FALSE)); - -// upsampling / downsampling -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rescale(FIBITMAP *dib, int dst_width, int dst_height, FREE_IMAGE_FILTER filter); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert FI_DEFAULT(TRUE)); - -// color manipulation routines (point operations) -DLL_API BOOL DLL_CALLCONV FreeImage_AdjustCurve(FIBITMAP *dib, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel); -DLL_API BOOL DLL_CALLCONV FreeImage_AdjustGamma(FIBITMAP *dib, double gamma); -DLL_API BOOL DLL_CALLCONV FreeImage_AdjustBrightness(FIBITMAP *dib, double percentage); -DLL_API BOOL DLL_CALLCONV FreeImage_AdjustContrast(FIBITMAP *dib, double percentage); -DLL_API BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *dib); -DLL_API BOOL DLL_CALLCONV FreeImage_GetHistogram(FIBITMAP *dib, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel FI_DEFAULT(FICC_BLACK)); -DLL_API int DLL_CALLCONV FreeImage_GetAdjustColorsLookupTable(BYTE *LUT, double brightness, double contrast, double gamma, BOOL invert); -DLL_API BOOL DLL_CALLCONV FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert FI_DEFAULT(FALSE)); -DLL_API unsigned DLL_CALLCONV FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap); -DLL_API unsigned DLL_CALLCONV FreeImage_SwapColors(FIBITMAP *dib, RGBQUAD *color_a, RGBQUAD *color_b, BOOL ignore_alpha); -DLL_API unsigned DLL_CALLCONV FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices, BYTE *dstindices, unsigned count, BOOL swap); -DLL_API unsigned DLL_CALLCONV FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b); - -// channel processing routines -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetChannel(FIBITMAP *dib, FREE_IMAGE_COLOR_CHANNEL channel); -DLL_API BOOL DLL_CALLCONV FreeImage_SetChannel(FIBITMAP *dib, FIBITMAP *dib8, FREE_IMAGE_COLOR_CHANNEL channel); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); -DLL_API BOOL DLL_CALLCONV FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); - -// copy / paste / composite routines -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Copy(FIBITMAP *dib, int left, int top, int right, int bottom); -DLL_API BOOL DLL_CALLCONV FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg FI_DEFAULT(FALSE), RGBQUAD *appBkColor FI_DEFAULT(NULL), FIBITMAP *bg FI_DEFAULT(NULL)); -DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom); -DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom); -DLL_API BOOL DLL_CALLCONV FreeImage_PreMultiplyWithAlpha(FIBITMAP *dib); - -// background filling routines -DLL_API BOOL DLL_CALLCONV FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_EnlargeCanvas(FIBITMAP *src, int left, int top, int right, int bottom, const void *color, int options FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateEx(int width, int height, int bpp, const RGBQUAD *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); - -// miscellaneous algorithms -DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle FI_DEFAULT(3)); - -// restore the borland-specific enum size option -#if defined(__BORLANDC__) -#pragma option pop -#endif - -#ifdef __cplusplus -} -#endif - -#endif // FREEIMAGE_H +// ========================================================== +// FreeImage 3 +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@infonie.fr) +// +// Contributors: +// - see changes log named 'Whatsnew.txt', see header of each .h and .cpp file +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef FREEIMAGE_H +#define FREEIMAGE_H + +// Version information ------------------------------------------------------ + +#define FREEIMAGE_MAJOR_VERSION 3 +#define FREEIMAGE_MINOR_VERSION 15 +#define FREEIMAGE_RELEASE_SERIAL 4 + +// Compiler options --------------------------------------------------------- + +#include // needed for UNICODE functions + +#if defined(FREEIMAGE_LIB) + #define DLL_API + #define DLL_CALLCONV +#else + #if defined(_WIN32) || defined(__WIN32__) + #define DLL_CALLCONV __stdcall + // The following ifdef block is the standard way of creating macros which make exporting + // from a DLL simpler. All files within this DLL are compiled with the FREEIMAGE_EXPORTS + // symbol defined on the command line. this symbol should not be defined on any project + // that uses this DLL. This way any other project whose source files include this file see + // DLL_API functions as being imported from a DLL, wheras this DLL sees symbols + // defined with this macro as being exported. + #ifdef FREEIMAGE_EXPORTS + #define DLL_API __declspec(dllexport) + #else + #define DLL_API __declspec(dllimport) + #endif // FREEIMAGE_EXPORTS + #else + // try the gcc visibility support (see http://gcc.gnu.org/wiki/Visibility) + #if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) + #ifndef GCC_HASCLASSVISIBILITY + #define GCC_HASCLASSVISIBILITY + #endif + #endif // __GNUC__ + #define DLL_CALLCONV + #if defined(GCC_HASCLASSVISIBILITY) + #define DLL_API __attribute__ ((visibility("default"))) + #else + #define DLL_API + #endif + #endif // WIN32 / !WIN32 +#endif // FREEIMAGE_LIB + +// Some versions of gcc may have BYTE_ORDER or __BYTE_ORDER defined +// If your big endian system isn't being detected, add an OS specific check +#if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#define FREEIMAGE_BIGENDIAN +#endif // BYTE_ORDER + +// This really only affects 24 and 32 bit formats, the rest are always RGB order. +#define FREEIMAGE_COLORORDER_BGR 0 +#define FREEIMAGE_COLORORDER_RGB 1 +#if defined(FREEIMAGE_BIGENDIAN) +#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB +#else +#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR +#endif + +// Ensure 4-byte enums if we're using Borland C++ compilers +#if defined(__BORLANDC__) +#pragma option push -b +#endif + +// For C compatibility -------------------------------------------------------- + +#ifdef __cplusplus +#define FI_DEFAULT(x) = x +#define FI_ENUM(x) enum x +#define FI_STRUCT(x) struct x +#else +#define FI_DEFAULT(x) +#define FI_ENUM(x) typedef int x; enum x +#define FI_STRUCT(x) typedef struct x x; struct x +#endif + +// Bitmap types ------------------------------------------------------------- + +FI_STRUCT (FIBITMAP) { void *data; }; +FI_STRUCT (FIMULTIBITMAP) { void *data; }; + +// Types used in the library (directly copied from Windows) ----------------- + +#if defined(__MINGW32__) && defined(_WINDOWS_H) +#define _WINDOWS_ // prevent a bug in MinGW32 +#endif // __MINGW32__ + +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef NULL +#define NULL 0 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifndef _MSC_VER +// define portable types for 32-bit / 64-bit OS +#include +typedef int32_t BOOL; +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef int32_t LONG; +typedef int64_t INT64; +typedef uint64_t UINT64; +#else +// MS is not C99 ISO compliant +typedef long BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef long LONG; +typedef signed __int64 INT64; +typedef unsigned __int64 UINT64; +#endif // _MSC_VER + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +typedef struct tagRGBQUAD { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; +#else + BYTE rgbRed; + BYTE rgbGreen; + BYTE rgbBlue; +#endif // FREEIMAGE_COLORORDER + BYTE rgbReserved; +} RGBQUAD; + +typedef struct tagRGBTRIPLE { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +#else + BYTE rgbtRed; + BYTE rgbtGreen; + BYTE rgbtBlue; +#endif // FREEIMAGE_COLORORDER +} RGBTRIPLE; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +typedef struct tagBITMAPINFOHEADER{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER, *PBITMAPINFOHEADER; + +typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} BITMAPINFO, *PBITMAPINFO; + +#endif // _WINDOWS_ + +// Types used in the library (specific to FreeImage) ------------------------ + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +/** 48-bit RGB +*/ +typedef struct tagFIRGB16 { + WORD red; + WORD green; + WORD blue; +} FIRGB16; + +/** 64-bit RGBA +*/ +typedef struct tagFIRGBA16 { + WORD red; + WORD green; + WORD blue; + WORD alpha; +} FIRGBA16; + +/** 96-bit RGB Float +*/ +typedef struct tagFIRGBF { + float red; + float green; + float blue; +} FIRGBF; + +/** 128-bit RGBA Float +*/ +typedef struct tagFIRGBAF { + float red; + float green; + float blue; + float alpha; +} FIRGBAF; + +/** Data structure for COMPLEX type (complex number) +*/ +typedef struct tagFICOMPLEX { + /// real part + double r; + /// imaginary part + double i; +} FICOMPLEX; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +// Indexes for byte arrays, masks and shifts for treating pixels as words --- +// These coincide with the order of RGBQUAD and RGBTRIPLE ------------------- + +#ifndef FREEIMAGE_BIGENDIAN +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR +// Little Endian (x86 / MS Windows, Linux) : BGR(A) order +#define FI_RGBA_RED 2 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 0 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x00FF0000 +#define FI_RGBA_GREEN_MASK 0x0000FF00 +#define FI_RGBA_BLUE_MASK 0x000000FF +#define FI_RGBA_ALPHA_MASK 0xFF000000 +#define FI_RGBA_RED_SHIFT 16 +#define FI_RGBA_GREEN_SHIFT 8 +#define FI_RGBA_BLUE_SHIFT 0 +#define FI_RGBA_ALPHA_SHIFT 24 +#else +// Little Endian (x86 / MaxOSX) : RGB(A) order +#define FI_RGBA_RED 0 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 2 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x000000FF +#define FI_RGBA_GREEN_MASK 0x0000FF00 +#define FI_RGBA_BLUE_MASK 0x00FF0000 +#define FI_RGBA_ALPHA_MASK 0xFF000000 +#define FI_RGBA_RED_SHIFT 0 +#define FI_RGBA_GREEN_SHIFT 8 +#define FI_RGBA_BLUE_SHIFT 16 +#define FI_RGBA_ALPHA_SHIFT 24 +#endif // FREEIMAGE_COLORORDER +#else +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR +// Big Endian (PPC / none) : BGR(A) order +#define FI_RGBA_RED 2 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 0 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x0000FF00 +#define FI_RGBA_GREEN_MASK 0x00FF0000 +#define FI_RGBA_BLUE_MASK 0xFF000000 +#define FI_RGBA_ALPHA_MASK 0x000000FF +#define FI_RGBA_RED_SHIFT 8 +#define FI_RGBA_GREEN_SHIFT 16 +#define FI_RGBA_BLUE_SHIFT 24 +#define FI_RGBA_ALPHA_SHIFT 0 +#else +// Big Endian (PPC / Linux, MaxOSX) : RGB(A) order +#define FI_RGBA_RED 0 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 2 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0xFF000000 +#define FI_RGBA_GREEN_MASK 0x00FF0000 +#define FI_RGBA_BLUE_MASK 0x0000FF00 +#define FI_RGBA_ALPHA_MASK 0x000000FF +#define FI_RGBA_RED_SHIFT 24 +#define FI_RGBA_GREEN_SHIFT 16 +#define FI_RGBA_BLUE_SHIFT 8 +#define FI_RGBA_ALPHA_SHIFT 0 +#endif // FREEIMAGE_COLORORDER +#endif // FREEIMAGE_BIGENDIAN + +#define FI_RGBA_RGB_MASK (FI_RGBA_RED_MASK|FI_RGBA_GREEN_MASK|FI_RGBA_BLUE_MASK) + +// The 16bit macros only include masks and shifts, since each color element is not byte aligned + +#define FI16_555_RED_MASK 0x7C00 +#define FI16_555_GREEN_MASK 0x03E0 +#define FI16_555_BLUE_MASK 0x001F +#define FI16_555_RED_SHIFT 10 +#define FI16_555_GREEN_SHIFT 5 +#define FI16_555_BLUE_SHIFT 0 +#define FI16_565_RED_MASK 0xF800 +#define FI16_565_GREEN_MASK 0x07E0 +#define FI16_565_BLUE_MASK 0x001F +#define FI16_565_RED_SHIFT 11 +#define FI16_565_GREEN_SHIFT 5 +#define FI16_565_BLUE_SHIFT 0 + +// ICC profile support ------------------------------------------------------ + +#define FIICC_DEFAULT 0x00 +#define FIICC_COLOR_IS_CMYK 0x01 + +FI_STRUCT (FIICCPROFILE) { + WORD flags; // info flag + DWORD size; // profile's size measured in bytes + void *data; // points to a block of contiguous memory containing the profile +}; + +// Important enums ---------------------------------------------------------- + +/** I/O image format identifiers. +*/ +FI_ENUM(FREE_IMAGE_FORMAT) { + FIF_UNKNOWN = -1, + FIF_BMP = 0, + FIF_ICO = 1, + FIF_JPEG = 2, + FIF_JNG = 3, + FIF_KOALA = 4, + FIF_LBM = 5, + FIF_IFF = FIF_LBM, + FIF_MNG = 6, + FIF_PBM = 7, + FIF_PBMRAW = 8, + FIF_PCD = 9, + FIF_PCX = 10, + FIF_PGM = 11, + FIF_PGMRAW = 12, + FIF_PNG = 13, + FIF_PPM = 14, + FIF_PPMRAW = 15, + FIF_RAS = 16, + FIF_TARGA = 17, + FIF_TIFF = 18, + FIF_WBMP = 19, + FIF_PSD = 20, + FIF_CUT = 21, + FIF_XBM = 22, + FIF_XPM = 23, + FIF_DDS = 24, + FIF_GIF = 25, + FIF_HDR = 26, + FIF_FAXG3 = 27, + FIF_SGI = 28, + FIF_EXR = 29, + FIF_J2K = 30, + FIF_JP2 = 31, + FIF_PFM = 32, + FIF_PICT = 33, + FIF_RAW = 34 +}; + +/** Image type used in FreeImage. +*/ +FI_ENUM(FREE_IMAGE_TYPE) { + FIT_UNKNOWN = 0, // unknown type + FIT_BITMAP = 1, // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit + FIT_UINT16 = 2, // array of unsigned short : unsigned 16-bit + FIT_INT16 = 3, // array of short : signed 16-bit + FIT_UINT32 = 4, // array of unsigned long : unsigned 32-bit + FIT_INT32 = 5, // array of long : signed 32-bit + FIT_FLOAT = 6, // array of float : 32-bit IEEE floating point + FIT_DOUBLE = 7, // array of double : 64-bit IEEE floating point + FIT_COMPLEX = 8, // array of FICOMPLEX : 2 x 64-bit IEEE floating point + FIT_RGB16 = 9, // 48-bit RGB image : 3 x 16-bit + FIT_RGBA16 = 10, // 64-bit RGBA image : 4 x 16-bit + FIT_RGBF = 11, // 96-bit RGB float image : 3 x 32-bit IEEE floating point + FIT_RGBAF = 12 // 128-bit RGBA float image : 4 x 32-bit IEEE floating point +}; + +/** Image color type used in FreeImage. +*/ +FI_ENUM(FREE_IMAGE_COLOR_TYPE) { + FIC_MINISWHITE = 0, // min value is white + FIC_MINISBLACK = 1, // min value is black + FIC_RGB = 2, // RGB color model + FIC_PALETTE = 3, // color map indexed + FIC_RGBALPHA = 4, // RGB color model with alpha channel + FIC_CMYK = 5 // CMYK color model +}; + +/** Color quantization algorithms. +Constants used in FreeImage_ColorQuantize. +*/ +FI_ENUM(FREE_IMAGE_QUANTIZE) { + FIQ_WUQUANT = 0, // Xiaolin Wu color quantization algorithm + FIQ_NNQUANT = 1 // NeuQuant neural-net quantization algorithm by Anthony Dekker +}; + +/** Dithering algorithms. +Constants used in FreeImage_Dither. +*/ +FI_ENUM(FREE_IMAGE_DITHER) { + FID_FS = 0, // Floyd & Steinberg error diffusion + FID_BAYER4x4 = 1, // Bayer ordered dispersed dot dithering (order 2 dithering matrix) + FID_BAYER8x8 = 2, // Bayer ordered dispersed dot dithering (order 3 dithering matrix) + FID_CLUSTER6x6 = 3, // Ordered clustered dot dithering (order 3 - 6x6 matrix) + FID_CLUSTER8x8 = 4, // Ordered clustered dot dithering (order 4 - 8x8 matrix) + FID_CLUSTER16x16= 5, // Ordered clustered dot dithering (order 8 - 16x16 matrix) + FID_BAYER16x16 = 6 // Bayer ordered dispersed dot dithering (order 4 dithering matrix) +}; + +/** Lossless JPEG transformations +Constants used in FreeImage_JPEGTransform +*/ +FI_ENUM(FREE_IMAGE_JPEG_OPERATION) { + FIJPEG_OP_NONE = 0, // no transformation + FIJPEG_OP_FLIP_H = 1, // horizontal flip + FIJPEG_OP_FLIP_V = 2, // vertical flip + FIJPEG_OP_TRANSPOSE = 3, // transpose across UL-to-LR axis + FIJPEG_OP_TRANSVERSE = 4, // transpose across UR-to-LL axis + FIJPEG_OP_ROTATE_90 = 5, // 90-degree clockwise rotation + FIJPEG_OP_ROTATE_180 = 6, // 180-degree rotation + FIJPEG_OP_ROTATE_270 = 7 // 270-degree clockwise (or 90 ccw) +}; + +/** Tone mapping operators. +Constants used in FreeImage_ToneMapping. +*/ +FI_ENUM(FREE_IMAGE_TMO) { + FITMO_DRAGO03 = 0, // Adaptive logarithmic mapping (F. Drago, 2003) + FITMO_REINHARD05 = 1, // Dynamic range reduction inspired by photoreceptor physiology (E. Reinhard, 2005) + FITMO_FATTAL02 = 2 // Gradient domain high dynamic range compression (R. Fattal, 2002) +}; + +/** Upsampling / downsampling filters. +Constants used in FreeImage_Rescale. +*/ +FI_ENUM(FREE_IMAGE_FILTER) { + FILTER_BOX = 0, // Box, pulse, Fourier window, 1st order (constant) b-spline + FILTER_BICUBIC = 1, // Mitchell & Netravali's two-param cubic filter + FILTER_BILINEAR = 2, // Bilinear filter + FILTER_BSPLINE = 3, // 4th order (cubic) b-spline + FILTER_CATMULLROM = 4, // Catmull-Rom spline, Overhauser spline + FILTER_LANCZOS3 = 5 // Lanczos3 filter +}; + +/** Color channels. +Constants used in color manipulation routines. +*/ +FI_ENUM(FREE_IMAGE_COLOR_CHANNEL) { + FICC_RGB = 0, // Use red, green and blue channels + FICC_RED = 1, // Use red channel + FICC_GREEN = 2, // Use green channel + FICC_BLUE = 3, // Use blue channel + FICC_ALPHA = 4, // Use alpha channel + FICC_BLACK = 5, // Use black channel + FICC_REAL = 6, // Complex images: use real part + FICC_IMAG = 7, // Complex images: use imaginary part + FICC_MAG = 8, // Complex images: use magnitude + FICC_PHASE = 9 // Complex images: use phase +}; + +// Metadata support --------------------------------------------------------- + +/** + Tag data type information (based on TIFF specifications) + + Note: RATIONALs are the ratio of two 32-bit integer values. +*/ +FI_ENUM(FREE_IMAGE_MDTYPE) { + FIDT_NOTYPE = 0, // placeholder + FIDT_BYTE = 1, // 8-bit unsigned integer + FIDT_ASCII = 2, // 8-bit bytes w/ last byte null + FIDT_SHORT = 3, // 16-bit unsigned integer + FIDT_LONG = 4, // 32-bit unsigned integer + FIDT_RATIONAL = 5, // 64-bit unsigned fraction + FIDT_SBYTE = 6, // 8-bit signed integer + FIDT_UNDEFINED = 7, // 8-bit untyped data + FIDT_SSHORT = 8, // 16-bit signed integer + FIDT_SLONG = 9, // 32-bit signed integer + FIDT_SRATIONAL = 10, // 64-bit signed fraction + FIDT_FLOAT = 11, // 32-bit IEEE floating point + FIDT_DOUBLE = 12, // 64-bit IEEE floating point + FIDT_IFD = 13, // 32-bit unsigned integer (offset) + FIDT_PALETTE = 14, // 32-bit RGBQUAD + FIDT_LONG8 = 16, // 64-bit unsigned integer + FIDT_SLONG8 = 17, // 64-bit signed integer + FIDT_IFD8 = 18 // 64-bit unsigned integer (offset) +}; + +/** + Metadata models supported by FreeImage +*/ +FI_ENUM(FREE_IMAGE_MDMODEL) { + FIMD_NODATA = -1, + FIMD_COMMENTS = 0, // single comment or keywords + FIMD_EXIF_MAIN = 1, // Exif-TIFF metadata + FIMD_EXIF_EXIF = 2, // Exif-specific metadata + FIMD_EXIF_GPS = 3, // Exif GPS metadata + FIMD_EXIF_MAKERNOTE = 4, // Exif maker note metadata + FIMD_EXIF_INTEROP = 5, // Exif interoperability metadata + FIMD_IPTC = 6, // IPTC/NAA metadata + FIMD_XMP = 7, // Abobe XMP metadata + FIMD_GEOTIFF = 8, // GeoTIFF metadata + FIMD_ANIMATION = 9, // Animation metadata + FIMD_CUSTOM = 10, // Used to attach other metadata types to a dib + FIMD_EXIF_RAW = 11 // Exif metadata as a raw buffer +}; + +/** + Handle to a metadata model +*/ +FI_STRUCT (FIMETADATA) { void *data; }; + +/** + Handle to a FreeImage tag +*/ +FI_STRUCT (FITAG) { void *data; }; + +// File IO routines --------------------------------------------------------- + +#ifndef FREEIMAGE_IO +#define FREEIMAGE_IO + +typedef void* fi_handle; +typedef unsigned (DLL_CALLCONV *FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef unsigned (DLL_CALLCONV *FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef int (DLL_CALLCONV *FI_SeekProc) (fi_handle handle, long offset, int origin); +typedef long (DLL_CALLCONV *FI_TellProc) (fi_handle handle); + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +FI_STRUCT(FreeImageIO) { + FI_ReadProc read_proc; // pointer to the function used to read data + FI_WriteProc write_proc; // pointer to the function used to write data + FI_SeekProc seek_proc; // pointer to the function used to seek + FI_TellProc tell_proc; // pointer to the function used to aquire the current position +}; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +/** +Handle to a memory I/O stream +*/ +FI_STRUCT (FIMEMORY) { void *data; }; + +#endif // FREEIMAGE_IO + +// Plugin routines ---------------------------------------------------------- + +#ifndef PLUGINS +#define PLUGINS + +typedef const char *(DLL_CALLCONV *FI_FormatProc)(void); +typedef const char *(DLL_CALLCONV *FI_DescriptionProc)(void); +typedef const char *(DLL_CALLCONV *FI_ExtensionListProc)(void); +typedef const char *(DLL_CALLCONV *FI_RegExprProc)(void); +typedef void *(DLL_CALLCONV *FI_OpenProc)(FreeImageIO *io, fi_handle handle, BOOL read); +typedef void (DLL_CALLCONV *FI_CloseProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCountProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCapabilityProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef FIBITMAP *(DLL_CALLCONV *FI_LoadProc)(FreeImageIO *io, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_SaveProc)(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_ValidateProc)(FreeImageIO *io, fi_handle handle); +typedef const char *(DLL_CALLCONV *FI_MimeProc)(void); +typedef BOOL (DLL_CALLCONV *FI_SupportsExportBPPProc)(int bpp); +typedef BOOL (DLL_CALLCONV *FI_SupportsExportTypeProc)(FREE_IMAGE_TYPE type); +typedef BOOL (DLL_CALLCONV *FI_SupportsICCProfilesProc)(void); +typedef BOOL (DLL_CALLCONV *FI_SupportsNoPixelsProc)(void); + +FI_STRUCT (Plugin) { + FI_FormatProc format_proc; + FI_DescriptionProc description_proc; + FI_ExtensionListProc extension_proc; + FI_RegExprProc regexpr_proc; + FI_OpenProc open_proc; + FI_CloseProc close_proc; + FI_PageCountProc pagecount_proc; + FI_PageCapabilityProc pagecapability_proc; + FI_LoadProc load_proc; + FI_SaveProc save_proc; + FI_ValidateProc validate_proc; + FI_MimeProc mime_proc; + FI_SupportsExportBPPProc supports_export_bpp_proc; + FI_SupportsExportTypeProc supports_export_type_proc; + FI_SupportsICCProfilesProc supports_icc_profiles_proc; + FI_SupportsNoPixelsProc supports_no_pixels_proc; +}; + +typedef void (DLL_CALLCONV *FI_InitProc)(Plugin *plugin, int format_id); + +#endif // PLUGINS + + +// Load / Save flag constants ----------------------------------------------- + +#define FIF_LOAD_NOPIXELS 0x8000 // loading: load the image header only (not supported by all plugins, default to full loading) + +#define BMP_DEFAULT 0 +#define BMP_SAVE_RLE 1 +#define CUT_DEFAULT 0 +#define DDS_DEFAULT 0 +#define EXR_DEFAULT 0 // save data as half with piz-based wavelet compression +#define EXR_FLOAT 0x0001 // save data as float instead of as half (not recommended) +#define EXR_NONE 0x0002 // save with no compression +#define EXR_ZIP 0x0004 // save with zlib compression, in blocks of 16 scan lines +#define EXR_PIZ 0x0008 // save with piz-based wavelet compression +#define EXR_PXR24 0x0010 // save with lossy 24-bit float compression +#define EXR_B44 0x0020 // save with lossy 44% float compression - goes to 22% when combined with EXR_LC +#define EXR_LC 0x0040 // save images with one luminance and two chroma channels, rather than as RGB (lossy compression) +#define FAXG3_DEFAULT 0 +#define GIF_DEFAULT 0 +#define GIF_LOAD256 1 // Load the image as a 256 color image with ununsed palette entries, if it's 16 or 2 color +#define GIF_PLAYBACK 2 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading +#define HDR_DEFAULT 0 +#define ICO_DEFAULT 0 +#define ICO_MAKEALPHA 1 // convert to 32bpp and create an alpha channel from the AND-mask when loading +#define IFF_DEFAULT 0 +#define J2K_DEFAULT 0 // save with a 16:1 rate +#define JP2_DEFAULT 0 // save with a 16:1 rate +#define JPEG_DEFAULT 0 // loading (see JPEG_FAST); saving (see JPEG_QUALITYGOOD|JPEG_SUBSAMPLING_420) +#define JPEG_FAST 0x0001 // load the file as fast as possible, sacrificing some quality +#define JPEG_ACCURATE 0x0002 // load the file with the best quality, sacrificing some speed +#define JPEG_CMYK 0x0004 // load separated CMYK "as is" (use | to combine with other load flags) +#define JPEG_EXIFROTATE 0x0008 // load and rotate according to Exif 'Orientation' tag if available +#define JPEG_GREYSCALE 0x0010 // load and convert to a 8-bit greyscale image +#define JPEG_QUALITYSUPERB 0x80 // save with superb quality (100:1) +#define JPEG_QUALITYGOOD 0x0100 // save with good quality (75:1) +#define JPEG_QUALITYNORMAL 0x0200 // save with normal quality (50:1) +#define JPEG_QUALITYAVERAGE 0x0400 // save with average quality (25:1) +#define JPEG_QUALITYBAD 0x0800 // save with bad quality (10:1) +#define JPEG_PROGRESSIVE 0x2000 // save as a progressive-JPEG (use | to combine with other save flags) +#define JPEG_SUBSAMPLING_411 0x1000 // save with high 4x1 chroma subsampling (4:1:1) +#define JPEG_SUBSAMPLING_420 0x4000 // save with medium 2x2 medium chroma subsampling (4:2:0) - default value +#define JPEG_SUBSAMPLING_422 0x8000 // save with low 2x1 chroma subsampling (4:2:2) +#define JPEG_SUBSAMPLING_444 0x10000 // save with no chroma subsampling (4:4:4) +#define JPEG_OPTIMIZE 0x20000 // on saving, compute optimal Huffman coding tables (can reduce a few percent of file size) +#define JPEG_BASELINE 0x40000 // save basic JPEG, without metadata or any markers +#define KOALA_DEFAULT 0 +#define LBM_DEFAULT 0 +#define MNG_DEFAULT 0 +#define PCD_DEFAULT 0 +#define PCD_BASE 1 // load the bitmap sized 768 x 512 +#define PCD_BASEDIV4 2 // load the bitmap sized 384 x 256 +#define PCD_BASEDIV16 3 // load the bitmap sized 192 x 128 +#define PCX_DEFAULT 0 +#define PFM_DEFAULT 0 +#define PICT_DEFAULT 0 +#define PNG_DEFAULT 0 +#define PNG_IGNOREGAMMA 1 // loading: avoid gamma correction +#define PNG_Z_BEST_SPEED 0x0001 // save using ZLib level 1 compression flag (default value is 6) +#define PNG_Z_DEFAULT_COMPRESSION 0x0006 // save using ZLib level 6 compression flag (default recommended value) +#define PNG_Z_BEST_COMPRESSION 0x0009 // save using ZLib level 9 compression flag (default value is 6) +#define PNG_Z_NO_COMPRESSION 0x0100 // save without ZLib compression +#define PNG_INTERLACED 0x0200 // save using Adam7 interlacing (use | to combine with other save flags) +#define PNM_DEFAULT 0 +#define PNM_SAVE_RAW 0 // If set the writer saves in RAW format (i.e. P4, P5 or P6) +#define PNM_SAVE_ASCII 1 // If set the writer saves in ASCII format (i.e. P1, P2 or P3) +#define PSD_DEFAULT 0 +#define PSD_CMYK 1 // reads tags for separated CMYK (default is conversion to RGB) +#define PSD_LAB 2 // reads tags for CIELab (default is conversion to RGB) +#define RAS_DEFAULT 0 +#define RAW_DEFAULT 0 // load the file as linear RGB 48-bit +#define RAW_PREVIEW 1 // try to load the embedded JPEG preview with included Exif Data or default to RGB 24-bit +#define RAW_DISPLAY 2 // load the file as RGB 24-bit +#define RAW_HALFSIZE 4 // output a half-size color image +#define SGI_DEFAULT 0 +#define TARGA_DEFAULT 0 +#define TARGA_LOAD_RGB888 1 // If set the loader converts RGB555 and ARGB8888 -> RGB888. +#define TARGA_SAVE_RLE 2 // If set, the writer saves with RLE compression +#define TIFF_DEFAULT 0 +#define TIFF_CMYK 0x0001 // reads/stores tags for separated CMYK (use | to combine with compression flags) +#define TIFF_PACKBITS 0x0100 // save using PACKBITS compression +#define TIFF_DEFLATE 0x0200 // save using DEFLATE compression (a.k.a. ZLIB compression) +#define TIFF_ADOBE_DEFLATE 0x0400 // save using ADOBE DEFLATE compression +#define TIFF_NONE 0x0800 // save without any compression +#define TIFF_CCITTFAX3 0x1000 // save using CCITT Group 3 fax encoding +#define TIFF_CCITTFAX4 0x2000 // save using CCITT Group 4 fax encoding +#define TIFF_LZW 0x4000 // save using LZW compression +#define TIFF_JPEG 0x8000 // save using JPEG compression +#define TIFF_LOGLUV 0x10000 // save using LogLuv compression +#define WBMP_DEFAULT 0 +#define XBM_DEFAULT 0 +#define XPM_DEFAULT 0 + +// Background filling options --------------------------------------------------------- +// Constants used in FreeImage_FillBackground and FreeImage_EnlargeCanvas + +#define FI_COLOR_IS_RGB_COLOR 0x00 // RGBQUAD color is a RGB color (contains no valid alpha channel) +#define FI_COLOR_IS_RGBA_COLOR 0x01 // RGBQUAD color is a RGBA color (contains a valid alpha channel) +#define FI_COLOR_FIND_EQUAL_COLOR 0x02 // For palettized images: lookup equal RGB color from palette +#define FI_COLOR_ALPHA_IS_INDEX 0x04 // The color's rgbReserved member (alpha) contains the palette index to be used +#define FI_COLOR_PALETTE_SEARCH_MASK (FI_COLOR_FIND_EQUAL_COLOR | FI_COLOR_ALPHA_IS_INDEX) // No color lookup is performed + + +#ifdef __cplusplus +extern "C" { +#endif + +// Init / Error routines ---------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_DeInitialise(void); + +// Version routines --------------------------------------------------------- + +DLL_API const char *DLL_CALLCONV FreeImage_GetVersion(void); +DLL_API const char *DLL_CALLCONV FreeImage_GetCopyrightMessage(void); + +// Message output functions ------------------------------------------------- + +typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg); +typedef void (DLL_CALLCONV *FreeImage_OutputMessageFunctionStdCall)(FREE_IMAGE_FORMAT fif, const char *msg); + +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessageStdCall(FreeImage_OutputMessageFunctionStdCall omf); +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf); +DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt, ...); + +// Allocate / Clone / Unload routines --------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp FI_DEFAULT(8), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_Unload(FIBITMAP *dib); + +// Header loading routines +DLL_API BOOL DLL_CALLCONV FreeImage_HasPixels(FIBITMAP *dib); + +// Load / Save routines ----------------------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); + +// Memory I/O stream routines ----------------------------------------------- + +DLL_API FIMEMORY *DLL_CALLCONV FreeImage_OpenMemory(BYTE *data FI_DEFAULT(0), DWORD size_in_bytes FI_DEFAULT(0)); +DLL_API void DLL_CALLCONV FreeImage_CloseMemory(FIMEMORY *stream); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToMemory(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API long DLL_CALLCONV FreeImage_TellMemory(FIMEMORY *stream); +DLL_API BOOL DLL_CALLCONV FreeImage_SeekMemory(FIMEMORY *stream, long offset, int origin); +DLL_API BOOL DLL_CALLCONV FreeImage_AcquireMemory(FIMEMORY *stream, BYTE **data, DWORD *size_in_bytes); +DLL_API unsigned DLL_CALLCONV FreeImage_ReadMemory(void *buffer, unsigned size, unsigned count, FIMEMORY *stream); +DLL_API unsigned DLL_CALLCONV FreeImage_WriteMemory(const void *buffer, unsigned size, unsigned count, FIMEMORY *stream); + +DLL_API FIMULTIBITMAP *DLL_CALLCONV FreeImage_LoadMultiBitmapFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveMultiBitmapToMemory(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FIMEMORY *stream, int flags); + +// Plugin Interface --------------------------------------------------------- + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterExternalPlugin(const char *path, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); +DLL_API int DLL_CALLCONV FreeImage_GetFIFCount(void); +DLL_API int DLL_CALLCONV FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable); +DLL_API int DLL_CALLCONV FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFormat(const char *format); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromMime(const char *mime); +DLL_API const char *DLL_CALLCONV FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFMimeType(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilename(const char *filename); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilenameU(const wchar_t *filename); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportBPP(FREE_IMAGE_FORMAT fif, int bpp); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportType(FREE_IMAGE_FORMAT fif, FREE_IMAGE_TYPE type); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsICCProfiles(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsNoPixels(FREE_IMAGE_FORMAT fif); + +// Multipaging interface ---------------------------------------------------- + +DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory FI_DEFAULT(FALSE), int flags FI_DEFAULT(0)); +DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags FI_DEFAULT(0)); +DLL_API int DLL_CALLCONV FreeImage_GetPageCount(FIMULTIBITMAP *bitmap); +DLL_API void DLL_CALLCONV FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data); +DLL_API void DLL_CALLCONV FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data); +DLL_API void DLL_CALLCONV FreeImage_DeletePage(FIMULTIBITMAP *bitmap, int page); +DLL_API FIBITMAP * DLL_CALLCONV FreeImage_LockPage(FIMULTIBITMAP *bitmap, int page); +DLL_API void DLL_CALLCONV FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *data, BOOL changed); +DLL_API BOOL DLL_CALLCONV FreeImage_MovePage(FIMULTIBITMAP *bitmap, int target, int source); +DLL_API BOOL DLL_CALLCONV FreeImage_GetLockedPageNumbers(FIMULTIBITMAP *bitmap, int *pages, int *count); + +// Filetype request routines ------------------------------------------------ + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileType(const char *filename, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeU(const wchar_t *filename, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromMemory(FIMEMORY *stream, int size FI_DEFAULT(0)); + +// Image type request routine ----------------------------------------------- + +DLL_API FREE_IMAGE_TYPE DLL_CALLCONV FreeImage_GetImageType(FIBITMAP *dib); + +// FreeImage helper routines ------------------------------------------------ + +DLL_API BOOL DLL_CALLCONV FreeImage_IsLittleEndian(void); +DLL_API BOOL DLL_CALLCONV FreeImage_LookupX11Color(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); +DLL_API BOOL DLL_CALLCONV FreeImage_LookupSVGColor(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); + +// Pixel access routines ---------------------------------------------------- + +DLL_API BYTE *DLL_CALLCONV FreeImage_GetBits(FIBITMAP *dib); +DLL_API BYTE *DLL_CALLCONV FreeImage_GetScanLine(FIBITMAP *dib, int scanline); + +DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); +DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); +DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); +DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); + +// DIB info routines -------------------------------------------------------- + +DLL_API unsigned DLL_CALLCONV FreeImage_GetColorsUsed(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBPP(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetWidth(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetHeight(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetLine(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib); +DLL_API RGBQUAD *DLL_CALLCONV FreeImage_GetPalette(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterX(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterY(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res); +DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res); + +DLL_API BITMAPINFOHEADER *DLL_CALLCONV FreeImage_GetInfoHeader(FIBITMAP *dib); +DLL_API BITMAPINFO *DLL_CALLCONV FreeImage_GetInfo(FIBITMAP *dib); +DLL_API FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetRedMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetGreenMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBlueMask(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetTransparencyCount(FIBITMAP *dib); +DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled); +DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count); +DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparentIndex(FIBITMAP *dib, int index); +DLL_API int DLL_CALLCONV FreeImage_GetTransparentIndex(FIBITMAP *dib); + +DLL_API BOOL DLL_CALLCONV FreeImage_HasBackgroundColor(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); +DLL_API BOOL DLL_CALLCONV FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetThumbnail(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail); + +// ICC profile routines ----------------------------------------------------- + +DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_GetICCProfile(FIBITMAP *dib); +DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size); +DLL_API void DLL_CALLCONV FreeImage_DestroyICCProfile(FIBITMAP *dib); + +// Line conversion routines ------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To4(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels); + +// Smart conversion routines ------------------------------------------------ + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo4Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo8Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToGreyscale(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits555(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits565(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo24Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo32Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize FI_DEFAULT(FIQ_WUQUANT), int PaletteSize FI_DEFAULT(256), int ReserveSize FI_DEFAULT(0), RGBQUAD *ReservePalette FI_DEFAULT(NULL)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Threshold(FIBITMAP *dib, BYTE T); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Dither(FIBITMAP *dib, FREE_IMAGE_DITHER algorithm); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToFloat(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToUINT16(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGB16(FIBITMAP *dib); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToStandardType(FIBITMAP *src, BOOL scale_linear FI_DEFAULT(TRUE)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear FI_DEFAULT(TRUE)); + +// tone mapping operators +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ToneMapping(FIBITMAP *dib, FREE_IMAGE_TMO tmo, double first_param FI_DEFAULT(0), double second_param FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoDrago03(FIBITMAP *src, double gamma FI_DEFAULT(2.2), double exposure FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0), double adaptation FI_DEFAULT(1), double color_correction FI_DEFAULT(0)); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoFattal02(FIBITMAP *src, double color_saturation FI_DEFAULT(0.5), double attenuation FI_DEFAULT(0.85)); + +// ZLib interface ----------------------------------------------------------- + +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size); + +// -------------------------------------------------------------------------- +// Metadata routines -------------------------------------------------------- +// -------------------------------------------------------------------------- + +// tag creation / destruction +DLL_API FITAG *DLL_CALLCONV FreeImage_CreateTag(void); +DLL_API void DLL_CALLCONV FreeImage_DeleteTag(FITAG *tag); +DLL_API FITAG *DLL_CALLCONV FreeImage_CloneTag(FITAG *tag); + +// tag getters and setters +DLL_API const char *DLL_CALLCONV FreeImage_GetTagKey(FITAG *tag); +DLL_API const char *DLL_CALLCONV FreeImage_GetTagDescription(FITAG *tag); +DLL_API WORD DLL_CALLCONV FreeImage_GetTagID(FITAG *tag); +DLL_API FREE_IMAGE_MDTYPE DLL_CALLCONV FreeImage_GetTagType(FITAG *tag); +DLL_API DWORD DLL_CALLCONV FreeImage_GetTagCount(FITAG *tag); +DLL_API DWORD DLL_CALLCONV FreeImage_GetTagLength(FITAG *tag); +DLL_API const void *DLL_CALLCONV FreeImage_GetTagValue(FITAG *tag); + +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagKey(FITAG *tag, const char *key); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagDescription(FITAG *tag, const char *description); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagID(FITAG *tag, WORD id); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagCount(FITAG *tag, DWORD count); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagLength(FITAG *tag, DWORD length); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagValue(FITAG *tag, const void *value); + +// iterator +DLL_API FIMETADATA *DLL_CALLCONV FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag); +DLL_API BOOL DLL_CALLCONV FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag); +DLL_API void DLL_CALLCONV FreeImage_FindCloseMetadata(FIMETADATA *mdhandle); + +// metadata setter and getter +DLL_API BOOL DLL_CALLCONV FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag); +DLL_API BOOL DLL_CALLCONV FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag); + +// helpers +DLL_API unsigned DLL_CALLCONV FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src); + +// tag to C string conversion +DLL_API const char* DLL_CALLCONV FreeImage_TagToString(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make FI_DEFAULT(NULL)); + +// -------------------------------------------------------------------------- +// Image manipulation toolkit ----------------------------------------------- +// -------------------------------------------------------------------------- + +// rotation and flipping +/// @deprecated see FreeImage_Rotate +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateClassic(FIBITMAP *dib, double angle); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor FI_DEFAULT(NULL)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask); +DLL_API BOOL DLL_CALLCONV FreeImage_FlipHorizontal(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_FlipVertical(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(FALSE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(FALSE)); + +// upsampling / downsampling +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rescale(FIBITMAP *dib, int dst_width, int dst_height, FREE_IMAGE_FILTER filter); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert FI_DEFAULT(TRUE)); + +// color manipulation routines (point operations) +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustCurve(FIBITMAP *dib, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustGamma(FIBITMAP *dib, double gamma); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustBrightness(FIBITMAP *dib, double percentage); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustContrast(FIBITMAP *dib, double percentage); +DLL_API BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_GetHistogram(FIBITMAP *dib, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel FI_DEFAULT(FICC_BLACK)); +DLL_API int DLL_CALLCONV FreeImage_GetAdjustColorsLookupTable(BYTE *LUT, double brightness, double contrast, double gamma, BOOL invert); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert FI_DEFAULT(FALSE)); +DLL_API unsigned DLL_CALLCONV FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap); +DLL_API unsigned DLL_CALLCONV FreeImage_SwapColors(FIBITMAP *dib, RGBQUAD *color_a, RGBQUAD *color_b, BOOL ignore_alpha); +DLL_API unsigned DLL_CALLCONV FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices, BYTE *dstindices, unsigned count, BOOL swap); +DLL_API unsigned DLL_CALLCONV FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b); + +// channel processing routines +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetChannel(FIBITMAP *dib, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); + +// copy / paste / composite routines +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Copy(FIBITMAP *dib, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg FI_DEFAULT(FALSE), RGBQUAD *appBkColor FI_DEFAULT(NULL), FIBITMAP *bg FI_DEFAULT(NULL)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_PreMultiplyWithAlpha(FIBITMAP *dib); + +// background filling routines +DLL_API BOOL DLL_CALLCONV FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_EnlargeCanvas(FIBITMAP *src, int left, int top, int right, int bottom, const void *color, int options FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateEx(int width, int height, int bpp, const RGBQUAD *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); + +// miscellaneous algorithms +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle FI_DEFAULT(3)); + +// restore the borland-specific enum size option +#if defined(__BORLANDC__) +#pragma option pop +#endif + +#ifdef __cplusplus +} +#endif + +#endif // FREEIMAGE_H diff --git a/FreeImage/FreeImagePlus.h b/FreeImage/FreeImagePlus.h index b6406c19..28a8d723 100644 --- a/FreeImage/FreeImagePlus.h +++ b/FreeImage/FreeImagePlus.h @@ -121,14 +121,14 @@ class FIP_API fipImage : public fipObject Constructor @see FreeImage_AllocateT */ - fipImage(FREE_IMAGE_TYPE image_type = FIT_BITMAP, WORD width = 0, WORD height = 0, WORD bpp = 0); + fipImage(FREE_IMAGE_TYPE image_type = FIT_BITMAP, unsigned width = 0, unsigned height = 0, unsigned bpp = 0); /// Destructor virtual ~fipImage(); /** Image allocator @see FreeImage_AllocateT */ - BOOL setSize(FREE_IMAGE_TYPE image_type, WORD width, WORD height, WORD bpp, unsigned red_mask = 0, unsigned green_mask = 0, unsigned blue_mask = 0); + BOOL setSize(FREE_IMAGE_TYPE image_type, unsigned width, unsigned height, unsigned bpp, unsigned red_mask = 0, unsigned green_mask = 0, unsigned blue_mask = 0); /// Destroy image data virtual void clear(); //@} @@ -324,19 +324,19 @@ class FIP_API fipImage : public fipObject Returns the image width in pixels @see FreeImage_GetWidth */ - WORD getWidth() const; + unsigned getWidth() const; /** Returns the image height in pixels @see FreeImage_GetHeight */ - WORD getHeight() const; + unsigned getHeight() const; /** Returns the width of the bitmap in bytes rounded to the nearest DWORD. @see FreeImage_GetPitch */ - WORD getScanWidth() const; + unsigned getScanWidth() const; /** Returns a pointer to the FIBITMAP data. Used for direct access from FREEIMAGE functions @@ -381,14 +381,14 @@ class FIP_API fipImage : public fipObject When the image type is FIT_BITMAP, valid bitdepth can be 1, 4, 8, 16, 24 or 32. @see FreeImage_GetBPP, getImageType */ - WORD getBitsPerPixel() const; + unsigned getBitsPerPixel() const; /** Returns the width of the bitmap in bytes.
This is not the size of the scanline. @see FreeImage_GetLine, getScanWidth */ - WORD getLine() const; + unsigned getLine() const; /** Returns the bitmap resolution along the X axis, in pixels / cm @@ -428,13 +428,13 @@ class FIP_API fipImage : public fipObject Returns the palette size in bytes. @see FreeImage_GetColorsUsed */ - WORD getPaletteSize() const; + unsigned getPaletteSize() const; /** Retrieves the number of colours used in the bitmap. If the bitmap is non-palletised, 0 is returned. @see FreeImage_GetColorsUsed */ - WORD getColorsUsed() const; + unsigned getColorsUsed() const; /** Investigates the colour type of the bitmap. @@ -449,6 +449,39 @@ class FIP_API fipImage : public fipObject BOOL isGrayscale() const; //@} + /**@name Thumbnail access */ + //@{ + + /** + Retrieves a copy the thumbnail possibly attached to the bitmap + @return Returns TRUE if the thumbnail is present in the bitmap and successfully retrieved, returns FALSE otherwise + @see FreeImage_GetThumbnail + */ + BOOL getThumbnail(fipImage& image) const; + + /** + Attach a thumbnail to the bitmap + @return Returns TRUE if the thumbnail was successfully set, returns FALSE otherwise + @see FreeImage_SetThumbnail + */ + BOOL setThumbnail(const fipImage& image); + + /** + Check if the image has an embedded thumbnail + @return Returns TRUE if a thumbnail is present in the bitmap, returns FALSE otherwise + @see FreeImage_GetThumbnail + */ + BOOL hasThumbnail() const; + + /** + Clear the thumbnail possibly attached to the bitmap + @return Returns TRUE if successful, returns FALSe otherwise + @see FreeImage_SetThumbnail + */ + BOOL clearThumbnail(); + + //@} + /**@name Pixel access */ //@{ @@ -467,7 +500,7 @@ class FIP_API fipImage : public fipObject Use this function with getScanWidth to iterates through the pixels. @see FreeImage_GetScanLine, FreeImage documentation */ - BYTE* getScanLine(WORD scanline) const; + BYTE* getScanLine(unsigned scanline) const; /** Get the pixel index of a 1-, 4- or 8-bit palettized image at position (x, y), including range check (slow access). @@ -599,6 +632,13 @@ class FIP_API fipImage : public fipObject */ BOOL convertTo32Bits(); + /** + Converts the bitmap to a 32-bit float image. + @return Returns TRUE if successfull, FALSE otherwise. + @see FreeImage_ConvertToFloat + */ + BOOL convertToFloat(); + /** Converts the bitmap to a 96-bit RGBF image. @return Returns TRUE if successfull, FALSE otherwise. @@ -606,6 +646,20 @@ class FIP_API fipImage : public fipObject */ BOOL convertToRGBF(); + /** + Converts the bitmap to a 16-bit unsigned short image. + @return Returns TRUE if successfull, FALSE otherwise. + @see FreeImage_ConvertToUINT16 + */ + BOOL convertToUINT16(); + + /** + Converts the bitmap to a 48-bit RGB16 image. + @return Returns TRUE if successfull, FALSE otherwise. + @see FreeImage_ConvertToRGB16 + */ + BOOL convertToRGB16(); + /** Converts a High Dynamic Range image (48-bit RGB or 96-bit RGB Float) to a 24-bit RGB image. @param tmo Tone mapping operator @@ -838,7 +892,7 @@ class FIP_API fipImage : public fipObject @return Returns TRUE if the operation was successful, FALSE otherwise @see FreeImage_Rescale, FREE_IMAGE_FILTER */ - BOOL rescale(WORD new_width, WORD new_height, FREE_IMAGE_FILTER filter); + BOOL rescale(unsigned new_width, unsigned new_height, FREE_IMAGE_FILTER filter); /** @brief Creates a thumbnail image keeping aspect ratio @@ -847,7 +901,7 @@ class FIP_API fipImage : public fipObject @return Returns TRUE if the operation was successful, FALSE otherwise @see FreeImage_MakeThumbnail */ - BOOL makeThumbnail(WORD max_size, BOOL convert = TRUE); + BOOL makeThumbnail(unsigned max_size, BOOL convert = TRUE); //@} /**@name Image status */ @@ -942,7 +996,7 @@ class FIP_API fipWinImage : public fipImage /**@name Creation & Destruction */ //@{ /// Constructor - fipWinImage(FREE_IMAGE_TYPE image_type = FIT_BITMAP, WORD width = 0, WORD height = 0, WORD bpp = 0); + fipWinImage(FREE_IMAGE_TYPE image_type = FIT_BITMAP, unsigned width = 0, unsigned height = 0, unsigned bpp = 0); /// Destructor virtual ~fipWinImage(); @@ -1134,6 +1188,12 @@ public : */ virtual ~fipMemoryIO(); + /** Destructor. + Free any allocated memory and invalidate the stream + @see FreeImage_CloseMemory + */ + void close(); + /** Returns TRUE if the internal memory buffer is a valid buffer, returns FALSE otherwise */ BOOL isValid() const; @@ -1162,6 +1222,14 @@ public : */ FIBITMAP* load(FREE_IMAGE_FORMAT fif, int flags = 0) const; /** + Loads a multi-page bitmap from a memory stream + @param fif Format identifier (FreeImage format) + @param flags The signification of this flag depends on the multi-page to be loaded. + @return Returns the loaded multi-page if successful, returns NULL otherwise + @see FreeImage_LoadMultiBitmapFromMemory + */ + FIMULTIBITMAP* loadMultiPage(FREE_IMAGE_FORMAT fif, int flags = 0) const; + /** Saves a dib to a memory stream @param fif Format identifier (FreeImage format) @param dib Image to be saved @@ -1171,6 +1239,15 @@ public : */ BOOL save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, int flags = 0); /** + Saves a multi-page bitmap to a memory stream + @param fif Format identifier (FreeImage format) + @param bitmap Multi-page image to be saved + @param flags The signification of this flag depends on the image to be saved. + @return Returns TRUE if successful, returns FALSE otherwise + @see FreeImage_SaveMultiBitmapToMemory + */ + BOOL saveMultiPage(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, int flags = 0); + /** Reads data from a memory stream @param buffer Storage location for data @param size Item size in bytes @@ -1247,7 +1324,15 @@ class FIP_API fipMultiPage : public fipObject BOOL isValid() const; /** - Open a file stream + Returns a pointer to the FIMULTIBITMAP data. Used for direct access from FREEIMAGE functions + or from your own low level C functions. + */ + operator FIMULTIBITMAP*() { + return _mpage; + } + + /** + Open a multi-page file stream @param lpszPathName Name of the multi-page bitmap file @param create_new When TRUE, it means that a new bitmap will be created rather than an existing one being opened @param read_only When TRUE the bitmap is opened read-only @@ -1258,7 +1343,7 @@ class FIP_API fipMultiPage : public fipObject BOOL open(const char* lpszPathName, BOOL create_new, BOOL read_only, int flags = 0); /** - Open a multi-page memory stream as read only. + Open a multi-page memory stream as read/write. @param memIO Memory stream. The memory stream MUST BE a wrapped user buffer. @param flags Load flags. The signification of this flag depends on the image to be loaded. @return Returns TRUE if successful, returns FALSE otherwise @@ -1266,6 +1351,16 @@ class FIP_API fipMultiPage : public fipObject */ BOOL open(fipMemoryIO& memIO, int flags = 0); + /** + Open a multi-page image as read/write, using the specified FreeImageIO struct and fi_handle, and an optional flag. + @param io FreeImageIO structure + @param handle FreeImage fi_handle + @param flag The signification of this flag depends on the image to be read. + @return Returns TRUE if successful, FALSE otherwise. + @see FreeImage_OpenMultiBitmapFromHandle + */ + BOOL open(FreeImageIO *io, fi_handle handle, int flags = 0); + /** Close a file stream @param flags Save flags. The signification of this flag depends on the image to be saved. @@ -1274,6 +1369,27 @@ class FIP_API fipMultiPage : public fipObject */ BOOL close(int flags = 0); + /** + Saves a multi-page image using the specified FreeImageIO struct and fi_handle, and an optional flag. + @param fif Format identifier (FreeImage format) + @param io FreeImageIO structure + @param handle FreeImage fi_handle + @param flag The signification of this flag depends on the multi-page image to be saved. + @return Returns TRUE if successful, FALSE otherwise. + @see FreeImage_SaveMultiBitmapToHandle, FreeImage documentation + */ + BOOL saveToHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags = 0) const; + + /** + Saves a multi-page image using the specified memory stream and an optional flag. + @param fif Format identifier (FreeImage format) + @param memIO FreeImage memory stream + @param flag The signification of this flag depends on the image to be saved. + @return Returns TRUE if successful, FALSE otherwise. + @see FreeImage_SaveMultiBitmapToMemory, FreeImage documentation + */ + BOOL saveToMemory(FREE_IMAGE_FORMAT fif, fipMemoryIO& memIO, int flags = 0) const; + /** Returns the number of pages currently available in the multi-paged bitmap @see FreeImage_GetPageCount diff --git a/FreeImage/FreeImagePlus.lib b/FreeImage/FreeImagePlus.lib index 6b0d1cf2..d56a32eb 100644 Binary files a/FreeImage/FreeImagePlus.lib and b/FreeImage/FreeImagePlus.lib differ diff --git a/FreeImage/x64/FreeImagePlus.lib b/FreeImage/x64/FreeImagePlus.lib index d9ce1fd1..2c9a0fb5 100644 Binary files a/FreeImage/x64/FreeImagePlus.lib and b/FreeImage/x64/FreeImagePlus.lib differ diff --git a/README.md b/README.md new file mode 100644 index 00000000..aa0a29ae --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +ConsoleZ +======== + +This is a modified version of Console 2 for a better experience under Windows Vista/7/8 and a better visual rendering. + +This fork supports: + + + splittable tabs (horizontally and vertically) + + Windows Vista aero glass theme + + Windows 7 jumplist + + Windows 8 wallpaper positions and slideshow + + Zooming with Ctrl-Mouse + + Quake style console animation + + strict monospace font rendering + +Changelog +========= + + * : fixed + - : removed + ! : changed + + : added + +Changes in 1.05.0 (2 Feb 2013) + + ! FreeImage 3.15.4 + ! Visual Studio 2012 + ! force monospace displaying + by adjusting the size of chars larger than average width font + ! limit vertical scrolling to the furthest buffer location viewed + ! WTL 8.1.12085 + + Windows 8 can use a wallpaper per monitor + + display a closing confirmation when there is only one tab + but multiple views + + improve the status bar with: + console buffer size, console screen size, + selection size and console PID + * dropping a file affects all views in a group + * aero glass margins are resetted when composition change + (hibernation disables DWM, at wakeup ConsoleZ was fully transparent) diff --git a/TabbingFramework/CustomTabCtrl.h b/TabbingFramework/CustomTabCtrl.h index c36c573e..a2408aed 100644 --- a/TabbingFramework/CustomTabCtrl.h +++ b/TabbingFramework/CustomTabCtrl.h @@ -453,6 +453,35 @@ class CCustomTabItem m_sText = sNewText; return true; } + virtual LONG GetTextSize(WTL::CClientDC& dc) const + { +#ifdef _USE_AERO + RECT rcText = { 0 }; + TCHAR szTitle[256]; + int szTitleLen = _sntprintf_s(szTitle, 256, _TRUNCATE, _T("0. %s"), this->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 { @@ -1375,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)) { @@ -1386,8 +1417,8 @@ class ATL_NO_VTABLE CCustomTabCtrl : { m_dwState |= ectcMouseInWindow; - pT->UpdateLayout(); - this->Invalidate(); + //pT->UpdateLayout(); + //this->Invalidate(); // "OnMouseEnter" //... @@ -1409,8 +1440,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); @@ -1441,8 +1474,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); @@ -1473,8 +1507,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); @@ -1505,8 +1540,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); @@ -1551,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; } @@ -1562,10 +1604,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; } @@ -2126,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) @@ -2141,6 +2189,7 @@ class ATL_NO_VTABLE CCustomTabCtrl : } } } + } return 0; } @@ -2318,10 +2367,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; @@ -2357,6 +2403,7 @@ class ATL_NO_VTABLE CCustomTabCtrl : { RECT rcItemDP = {0}; this->GetItemRect(i, &rcItemDP); + ::IntersectRect(&rcIntersect, &rcItemDP, &m_rcTabItemArea); // NOTE: Even if IntersectRect determines the rectangles @@ -2456,6 +2503,14 @@ class ATL_NO_VTABLE CCustomTabCtrl : pnmcd->hdc = dc; pnmcd->uItemState = 0; +#if 0 + CBufferedPaint bufferedPaint; + HDC hDCPaint = NULL; + BP_PAINTPARAMS paintParams = { sizeof(BP_PAINTPARAMS), BPPF_ERASE, NULL, NULL }; + bufferedPaint.Begin(dc, &rcClient, BPBF_TOPDOWNDIB, &paintParams, &hDCPaint); + pnmcd->hdc = hDCPaint; +#endif + pT->InitializeDrawStruct(&nmc); pnmcd->dwDrawStage = CDDS_PREPAINT; @@ -2569,7 +2624,12 @@ class ATL_NO_VTABLE CCustomTabCtrl : { pT->DoPostPaint(rcClient, &nmc); } - + +#if 0 + bufferedPaint.End(); + pnmcd->hdc = dc; +#endif + if( CDRF_NOTIFYPOSTPAINT == (lResCustom & CDRF_NOTIFYPOSTPAINT) ) { pnmcd->dwDrawStage = CDDS_POSTPAINT; 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..6bb2adf4 100644 --- a/TabbingFramework/TabbedFrame.h +++ b/TabbingFramework/TabbedFrame.h @@ -321,9 +321,7 @@ class CCustomTabOwnerImpl } } - // A derived class might not need to override this although they can. - // (but they will probably need to specialize SetTabAreaHeight) - void CalcTabAreaHeight(void) + int CalcTabAreaHeight2(void) { // Dynamically figure out a reasonable tab area height // based on the tab's font metrics @@ -353,7 +351,14 @@ class CCustomTabOwnerImpl } } - int nNewTabAreaHeight = nNominalHeight + ( ::MulDiv(nNominalHeight, nFontLogicalUnits, nNominalFontLogicalUnits) - nNominalHeight ) / 2; + return nNominalHeight + ( ::MulDiv(nNominalHeight, nFontLogicalUnits, nNominalFontLogicalUnits) - nNominalHeight ) / 2; + } + + // A derived class might not need to override this although they can. + // (but they will probably need to specialize SetTabAreaHeight) + void CalcTabAreaHeight(void) + { + int nNewTabAreaHeight = CalcTabAreaHeight2(); T* pT = static_cast(this); pT->SetTabAreaHeight(nNewTabAreaHeight); @@ -845,8 +850,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 @@ -1214,6 +1225,35 @@ class CTabbedFrameImpl : customTabOwnerClass::OnRemoveTab(nNewTabCount); } +#ifdef _USE_AERO + void CalcTabAreaHeight(void) + { + SIZE size; + + HTHEME hTheme = ::OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); + + ::GetThemePartSize( + hTheme, + NULL, + NAV_BACKBUTTON, + 0, + NULL, + TS_TRUE, + &size + ); + + ::CloseThemeData(hTheme); + + int nNewTabAreaHeight2 = customTabOwnerClass::CalcTabAreaHeight2(); + int nNewTabAreaHeight = max(size.cy + 4, nNewTabAreaHeight2); + + this->GetTabCtrl().SetTopMargin(nNewTabAreaHeight - nNewTabAreaHeight2); + + T* pT = static_cast(this); + pT->SetTabAreaHeight(nNewTabAreaHeight); + } +#endif + void SetTabAreaHeight(int nNewTabAreaHeight) { if(m_bKeepTabsHidden) diff --git a/devel_changes.txt b/devel_changes.txt deleted file mode 100644 index 09980544..00000000 --- a/devel_changes.txt +++ /dev/null @@ -1,427 +0,0 @@ -v2.00 -===== - -Build 146 -========= - -- a better Win7 lockup fix (again, thanks to akirill for the patch :-) - -- removed msv*90.dll dependencies - -- better error messages on shell startup - -- dump buffer now dumps to %TEMP%\console.dump - -- configuration load fix - -- better handling of windows settings' change - -- added 64-bit build - -- most fixes in this build are by Kirill :-) - - -Build 145 -========= - -- [BR#2722494] alpha transparency is now set properly for a pinned-to-desktop - Console window - -- [BR#2547017] Tab tooltips now show complete title (thanks to Phillip Foose for the patch) - -- a small speed optimization for relative backgrounds - -- fixed Win7 lockup (thanks to akirill for the patch) - - -Build 144 ---------- - -- tray icon settings were not always observed, fixed - -- optimized text repaint for relative backgrounds - - -Build 143 ---------- - -- [BR#2569915] Console buffer rows can now be set to max 9999 using arrows in - the settings dialog - -- invalid console cursor coordinates calculation lead to crash when leaving Console - window while selecting text - -- [BR#2555908] If there was only one tab defined on Console startup, that tab could - be deleted. This would crash Console - -- another attempt at fixing ClearType problems - - -Build 142 ---------- - -- [BR#2214144] Console will add a backslash to startup dirs that don't end with - a backslash. This will fix problems with startup dir defined as 'C:'. Updated - documentation for -d parameter - -- selection start will now pause window scrolling (e.g. a long dir command). ESC wil - unpause it (but it will not clear the selection) Clearing the selection (copy or not) - will re-enable scrolling - -- added 'stop scrolling' command (and a hotkey) (ESC re-enables) - -- added option for starting Windows console window hidden (previous behavior, was causing - problems with some GUI apps started from Console) - - -Build 141 ---------- - -- Console will now inherit environment block on startup (it used to get a fresh - environment block in b140); it will still track changes in the environment, like - it was implemented in b140 - -- Console is now restored if minimized when activated using a global hotkey - -- [BR#1969628] fixed a painting problem with applications that reduce buffer size - -- [BR#2114134] attempt at fixing the crash caused by a new process exiting before new - Console tab is initialized - - -Build 140 ---------- - -- [BR#1919569] attempt at fixing problems with invisible GUI apps started from Console - (this solution does cause console window's taskbar button to flash briefly) - -- upgraded to Visual Studio 2008 - -- updated several function calls that got 'depreciated' warnings when built with VS 2008 - -- pasting is now done using Windows' console 'paste' command - -- Console now tracks environment variables' changes (new tabs are opened with the latest - set of environment variables) - -- [BR#2026519] Console now handles resizing by other apps properly - -- added support for a global hotkey for activating Console - - -Build 139 ---------- - -- [FR#1529565] scrollbars can be hidden now - -- [BR#1876652] redone painting a bit, memory usage lower - - -Build 138 ---------- - -- [internal] (yet another) attempt at fixing text repainting - moved all GDI - calls to the main thread - - -Build 137 ---------- - -- [internal] (another) attempt at fixing text repainting problems (many thans - to akirill for help) - -- [BR#1848984] resizing Console will not flash inactive tabs - - -Build 136 ---------- - -- [internal] attempt at fix text repainting problems reported by several users - - -Build 135 ---------- - -- [internal] all bitmaps are now DIBs. Mixing DDBs and DIBs was causing - problems with multiple monitors and relative backgrounds - -- [internal] character buffer is initialized with spaces - -- [internal] fixed a problem with double-width characters (introduced when - fixing ClearType artifacts) - - -Build 134 ---------- - -- [BR#1808717] attempt at fixing the disappearing text bug; this may fix some - other bugs - - -Build 133 ---------- - -- [BR#1780513] fixed a problem with long lines being wrapped when they - shouldn't - -- [BR#1524127] fixed a problem (workaround) with ALT+SPACE not showing the - system menu (thanks to akirill for the patch) - -- [FR#1725807] added some inactive tab flashing configuration options - -- [BR#1814653] fixed a screen lock-up on mouse click during fast screen - changes - -- mouse messages are discarded when Console window is activated using the - mouse - this will prevent things like starting a selection when activating - a Console window - -- [FR#1722611] you can now set selection color - -- [BR#1732360] attempt at fixing the newline problem - - -Build 132 ---------- - -- fixed a problem with ClearType artifacts - -- [internal] attempt to fix new tab's initial painting problems - -- fixed 'disappear when dragged' bug for multiple monitors - -- font dialog now shows only fixed-pitch fonts (thanks to Anduin Withers for - the patch) - -- [internal] fixed a critical lock deadlock causing problems on Vista - -- [FR#1718013] middle click on an empty place on a tab bar will open a new - default tab - -- [FR#1725807] inactive tabs will flash three times if there is activity - - -Build 131 ---------- - -- [internal] fixed a problem with runas and local settings - -- added 'clear selection on copy' option - -- added customizable newline character for mulitline copy - -- added font smoothing settings - -- [internal] Console now checks that saved window position is inside desktop - -- 'Dump screen buffer' command now dumps visible text to C:\console.dump - -- added -w command line option for setting main window title; it overrides all - other main window title settings (e.g. 'use tab titles' setting) - -- for blinking cursors, blinking rates are now proporional to caret blinking - rate set in Control Panel - -- added 'clear selection' commands to menu and hotkeys; mouse 'copy' command - description is now 'Copy/clear selection' - - -Build 130 ---------- - -- fixed a disappearing selection while scrolling bug - -- fixed a scrolling upwards while selecting text bug - -- Console handles wallpaper changes now - -- fixed a small background color problem - -- added support for environment variables in config file name, shell command - line, startup directory, icons and background images - -- [internal] wallpaper changes, non-relative background image resizing and tab - switching should be thread safe now - -- mouse cursor is changed to 'text select' cursor while selecting - -- added drop down menu to 'new tab' toolbar button - -- [internal] an attempt to fix freezing when copying/pasting while a command - is running - - -Build 129 ---------- - -- fixed small bugs with mouse event forwarding (mouse move, some mouse clicks) - -- fixed a bug with scrolling hotkeys - -- (finally) window resizing works reliably - -- fixed a newline problem (I hope :-) - -- settings can be saved to user's APPDATA directory - - -Build 128 ---------- - -- added 'Clear' button to hotkeys dialog - -- added 'Use Scroll Lock for scrolling' option to hotkeys dialog; if on, arrow - keys and page up/down keys are used for scrolling when Scroll Lock is on - -- improved cursor rendering a bit - -- improved selection handling: - - selection now selects entire buffer row, not just the visible part - - scrolling with active selection works as expected - - you can now scroll Console window while selecting text - -- improved copy operation, entire buffer row is now copied (not just the - visible part) - -- added hotkeys for scrolling - -- added basic mouse events support - -- fixed a small bug with tab and window name updating - -- fixed a bug with pasting large text - -- added support for configurable mouse commands - - -Build 127 ---------- - -- added "Exit Console" command - -- added .bat and .cmd file types to "open shell" dialog - -- fixed a small background tinting problem - -- fixed a problem with non-black solid backgrounds - -- fixed a problem with client area mouse-dragging with cursor near left or top - edge - -- File->Tabs menu is updated properly after closing the settings dialog - -- [internal] implemented a fallback mechanism for allocating bitmaps - -- fixed broken buffer position after window resize - -- [internal] implemented proper rendering of double-width characters (Chinese, - Japanese) - - -Build 126 ---------- - -- implemented window size saving - -- implemented window position saving - -- [internal] custom handling for WM_SYSKEYDOWN and WM_SYSKEYUP messages (they - are not translated); this should pass all keystrokes to console (WM_KEYDOWN - and WM_KEYUP are already handled this way) - -- added ClearType support; it works for 32bit color settings only - -- fixed a little bug with tray icon - -- ALT+ENTER doesn't switch real console to full screen - - -Build 125 ---------- - -- fixed rows/columns display updating in the statusbar - -- added support for multiple startup tabs, dirs and commands (-t, -d and - -ts cmd-line options) - -- added command line option for startup command (-r) - -- added help support - -- added Help command - -- fixed 'dead' characters input - -- [internal] improved hotkey handling - -- [internal] implemented directory existance check on new tab startup - - -Build 124 ---------- - -- [internal] '100% hang bug' fix is back. Test in Build 123 didn't work :-) - -- XTerm cursor now inverts characters underneath it - - -Build 123 ---------- - -- SCROLL LOCK can now be used for scrolling: when on, you can scroll Console - window using PageUp/Down and arrow keys (thanks to jachymko for submitting - the patch) - -- drag 'n' dropped filenames are always enclosed in quotes - -- middle click closes tab - -- added tooltips to toolbar buttons - -- About box shows Console version info (major, minor and build numbers) - -- rows and columns info is shown in the statusbar - -- disabled the maximize box until I implement proper maximize support - - -Build 122 ---------- - -- [internal] reduced buffer size in ReadConsoleOutput call in ConsoleHook; - caused errors with large windows - -- [internal] attempted fix for '100% hang bug' - -- [internal] a small mem_fn fix in SharedMemoryLock class, thanks jachymko :-) - - -Build 121 ---------- - -- added 'pin to desktop' setting for Z-order (Windows Explorer only) - -- number of page scroll rows is configurable (either entire page or N rows) - -- toolbar improvements (nicer icons, more buttons) - -- Console has setup now! - -- menu, toolbar, tabs and status bar visibility persistent (from View menu) - -- trim tab titles option - -- drag'n'drop files support - -- added 'hide single tab' option - -- improved settings dialog (tab titles, etc) - - -Build 120 (initial beta build) ------------------------------- - -Changes since last demo version: - -- improved settings dialog - diff --git a/help/console.hhc b/help/console.hhc index b66ab794..e10968a2 100644 --- a/help/console.hhc +++ b/help/console.hhc @@ -40,6 +40,10 @@
    +
  • + + +
  • @@ -73,15 +77,9 @@ -
-
  • - - - -
    • - - + +
  • diff --git a/help/console.hhp b/help/console.hhp index 43231141..adb5efae 100644 --- a/help/console.hhp +++ b/help/console.hhp @@ -21,6 +21,7 @@ html\gpl.html html\acknowledgements.html html\running.html html\menus.html +html\settings.html html\settings_console.html html\settings_appearance.html html\settings_appearance_more.html @@ -30,9 +31,8 @@ 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 [INFOTYPES] 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, 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 :-) -

    -
      -
    • - No maximize support. I'm still not completely happy with the code, - so it's currently disabled. -
    • -
    • - Running tabs under different credentials. I plan to support 'run - as' for tabs, but it will have to wait for the next version. -
    • -
    • - Full screen mode. -
    • -
    • - Alpha transparency with desktop background doesn't work as - expected. I don't know why this happens. -
    • -
    • - There are several minor bugs and feature requests listed on - project's Sourceforge - page. You can monitor their status there. I will try to - fix/implement them as time permits... -
    • -
        - - - \ No newline at end of file diff --git a/help/html/copyright.html b/help/html/copyright.html index 1fa1cfb5..683ccf9d 100644 --- a/help/html/copyright.html +++ b/help/html/copyright.html @@ -9,9 +9,11 @@

        Copyright

        -

        - Console is Copyright (C) 2001-2007 Marko Bozikovic + ConsoleZ is Copyright (C) 2011-2012 Christophe Bucher +

        +

        + Console is Copyright (C) 2001-2011 Marko Bozikovic

        This program is free software; you can redistribute it and/or modify @@ -24,18 +26,6 @@

        Copyright

        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

        -

        - Send bug reports, bug fixes, enhancements, requests, flames, etc., and - I'll try to keep a version up to date. I can be reached as follows: -
        - bozho@kset.org -
        - marko.bozikovic@gmail.com -

        -

        - Console program icon is Copyright (C) 2001-2006 Ante Vukorepa - (orcinus@kset.org) -

        Console toolbar icons are Copyright (C) Mark James (mjames@gmail.com). The iconset used is Silk icon set 1.3, and can be found at 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 diff --git a/help/html/introduction.html b/help/html/introduction.html index 3b7e5dcc..91552b57 100644 --- a/help/html/introduction.html +++ b/help/html/introduction.html @@ -2,25 +2,28 @@ - Introduction to Console + Introduction to ConsoleZ -

        Introduction to Console

        +

        Introduction to ConsoleZ

        +

        + ConsoleZ is a fork of Console project. +

        Console is a Windows console window enhancement. It was inspired by eConsole (http://www.informatik.uni-frankfurt.de/~corion)

        - Console features include: + ConsoleZ features include:

          -
        • multiple tabs
        • +
        • multiple splittable tabs
        • text editor-like text selection
        • different background types (solid color, image, fake transparency)
        • -
        • alpha and color-key transparency
        • +
        • areo glass, alpha and color-key transparency
        • configurable font
        • different window styles
        @@ -39,6 +42,9 @@

        Introduction to Console

        Console is hosted on Sourceforge. Get the latest news and updates there.

        +

        + ConsoleZ is hosted on github. +

        \ No newline at end of file diff --git a/help/html/menus.html b/help/html/menus.html index 70784c0d..dea5d109 100644 --- a/help/html/menus.html +++ b/help/html/menus.html @@ -38,12 +38,24 @@

        Edit


        +

        Clear selection

        +

        + Clears current selection. +

        +
        +

        Paste

        Pastes text from clipboard.


        +

        Stop scrolling

        +

        + When a command produces a lot of output this action prevents the underlying console to scroll by switching to the Select mode. Hit Esc or Enter key to resume scrolling. +

        +
        +

        Rename Tab

        Renames current tab. diff --git a/help/html/reporting_problems.html b/help/html/reporting_problems.html deleted file mode 100644 index 1a7c2a64..00000000 --- a/help/html/reporting_problems.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - Reporting problems - - - - - -

        Reporting problems

        - -

        - Half of the work in fixing a bug can be done by properly reporting it. - Just creating a bug report and saying "This does not work" is clearly - not good enough. When fixing bugs, most of my time is usually wasted on - finding details for these bug reports. -

        -

        - Please follow these guidelines when reporting problems: -

        -
          -
        • - Please use Console's SF bug reporting page. - Reporting bugs elsewhere (like the forum) is not a good idea, since - they may get lost and forgotten. -
        • -
        • - Write Console and Windows version you're using. -
        • -
        • - Attach your configuration file. -
        • -
        • - Attach screenshots if they illustrate your problem. -
        • -
        • - If you can, describe in detail the symptoms and steps to reproduce - them. If I can't reproduce the bug, it's usually very difficult to - fix it. -
        • -
        • - If Console output seems strange/garbled/broken, unhide the hidden - console window (View->Console window). If its output looks the same, - it's probably not a Console issue. Some console applications can - behave strangely. -
        • -
        • - Try to eliminate other utilities you run that could interfere with - Console (hotkey managers, etc). -
        • -
            - - - \ No newline at end of file diff --git a/help/html/settings.html b/help/html/settings.html new file mode 100644 index 00000000..38f67491 --- /dev/null +++ b/help/html/settings.html @@ -0,0 +1,29 @@ + + + + + Settings - Console + + + + + +

            Settings - Console

            + +

            + +

            + +

            Save settings to user directory

            +

            + Settings are loaded from user directory by default. + If no settings are found in user directory they are loaded from the Console directory. + Setting are by default saved to where they have been loaded. + If for rights reason this is not possible settings are saved to user directory. + If "Save setting to user directory" is checked settings are saved to user directory in any cases. +

            +
            + + + + \ No newline at end of file diff --git a/help/html/settings_appearance.html b/help/html/settings_appearance.html index ba7fb5ac..afd2bd8e 100644 --- a/help/html/settings_appearance.html +++ b/help/html/settings_appearance.html @@ -18,13 +18,13 @@

            Title & icon

            Title

            - Specifies initial Console title. + Specifies the main window title.


            Use tab titles

            - If checked, main window title will be set to active tab's title. + If checked, main window title will be set to the active tab's title.


            @@ -56,6 +56,19 @@

            Title & icon


            +

            character width

            +

            + Specify the maximum number of character of the tab name. +

            +
            + +

            chars at end

            +

            + Specify the number of characters to take from the end of the string. + The total number will not exceed the character width. +

            +
            +

            Icon

            Specifies custom icon for the main window. If left empty, default @@ -108,7 +121,7 @@

            Font

            Position

            -

            Position window

            +

            Initial position

            When checked, allows you to specify initial window position. Otherwise, initial Console window position will be determined by Windows. @@ -133,7 +146,7 @@

            Position


            -

            Snap distance

            +

            Distance

            Specifies window snap disance.

            diff --git a/help/html/settings_appearance_more.html b/help/html/settings_appearance_more.html index 1831aa3f..ce51aed8 100644 --- a/help/html/settings_appearance_more.html +++ b/help/html/settings_appearance_more.html @@ -46,6 +46,24 @@

            Controls


            +

            Tabs on bottom

            +

            + If checked, tabs bar will appear at the bottom of the main window. +

            +
            + +

            Show scrollbars

            +

            + If checked, scrollbars will be shown if the underlying console shows them. + If not checked, scrollbars will be always hidden. +

            +
            + +

            Flat scrollbars

            +

            + If checked, the style of the scrollbars will be flat if available. +

            +

            Styles

            @@ -79,21 +97,41 @@

            Styles


            +

            Quake like

            +

            + If checked, Console use a quake console like effect when showing or hiding. +

            +
            + +

            Jumplist (Win7)

            +

            + If checked, Console will create Windows 7 jumplist (shortcut for every tab accessible by right-clicking the icon in the taskbar). +

            +
            +

            Inside border

            Specifies Console's inside (client area) border.


            +

            Selection color

            +

            + Sets the background color of the selection. The foreground color will be affected by this color. +

            +
            +

            Window transparency

            -

            None
            Alpha
            Color key

            +

            None
            Alpha
            Glass
            Color key

            Specifies transparency type.
            Alpha transparency is the 'real' transparency.
            + Vista aero glass effect. +
            Color key transparency allows you to specify a single color that will be made transparent. All window pixels having this color will be transparent and mouse clicks will pass through transparent areas. diff --git a/help/html/settings_behavior.html b/help/html/settings_behavior.html index 0c2bff6e..72452789 100644 --- a/help/html/settings_behavior.html +++ b/help/html/settings_behavior.html @@ -23,6 +23,18 @@

            Copy & paste


            +

            Clear selection on copy

            +

            + If checked, the selection will be cleared right after being copied. + For example, if Copy on select is not checked, you would need to either press + Copy selection hotkey or perform Copy/clear selection mouse action to + copy the selection to the system clipboard. If this checkbox is checked then + the selection will be cleared right after you perform one of those actions. Otherwise, + you will need to press Clear selection hotkey or perform Copy/clear selection + mouse action to return to the normal mode. +

            +
            +

            Don't wrap long lines

            If checked, long lines will not be wrapped. When a selected row @@ -52,6 +64,36 @@

            Page scrolling


            +

            Copy new line character

            + +

            Windows (CR+LF)

            +

            + If selected the copy operation will convert the carriage return using the Windows convention. +

            + +

            Unix (LF)

            +

            + If selected the copy operation will convert the carriage return using the Unix convention. +

            +
            + +

            Inactive tab activity flash

            + +

            Flash inactive tabs

            +

            + If checked, the inactive tabs flashes when some activities are detected in the corresponding console. +

            + +

            Falshes

            +

            + Indicate the number of times an inactive tab will flash when some activities are detected in the corresponding console. +

            + +

            Leave highlighted

            +

            + If checked, the inactive tab where some activities have been detected in the corresponding console will stay highlighted + even if the activities have stopped. +

            \ No newline at end of file diff --git a/help/html/settings_console.html b/help/html/settings_console.html index a8b8df1f..b049d7fa 100644 --- a/help/html/settings_console.html +++ b/help/html/settings_console.html @@ -29,6 +29,14 @@

            Shell


            +

            Start Windows console hidden

            +

            + Launch the underlying console app hidden. It prevents a flick in the Windows Taskbar.
            + Warning: some console applications, e.g. PowerShell, that open GUI windows may not work correctly + when this option is checked. +

            +
            +

            Update timeouts

            On change

            @@ -95,6 +103,8 @@

            Console colors map

            square shows the original color. Clicking on the right square will bring up a color picker allowing you to select a new color.
            + The opacity of the background color can be adjusted. +
            Reset button will reset colors to their default values.

            diff --git a/help/html/settings_tabs.html b/help/html/settings_tabs.html index 20e01112..8427b408 100644 --- a/help/html/settings_tabs.html +++ b/help/html/settings_tabs.html @@ -38,6 +38,11 @@

            Title & icon


            +

            Use default

            +

            + If checked, the default shell's icon will be used for this tab. +

            +

            Shell

            @@ -55,6 +60,12 @@

            Shell


            +

            +

            + If the checkbox is checked, a dialog, asking for another user's credentials will be displayed. + The dialog will be pre-populated with the given user name. +

            +

            Cursor

            @@ -113,7 +124,7 @@

            Background

            Position

            Select image position from the list. Background image can be centered, - stretched or tiled + stretched or tiled.
            "Fit" and "Fill" options generate a stretched image, keeping aspect ratio.


            diff --git a/help/images/settings.png b/help/images/settings.png new file mode 100644 index 00000000..f698d489 Binary files /dev/null and b/help/images/settings.png differ diff --git a/help/images/settings_appearance.png b/help/images/settings_appearance.png index f00d3074..a1af2eec 100644 Binary files a/help/images/settings_appearance.png and b/help/images/settings_appearance.png differ diff --git a/help/images/settings_appearance_more.png b/help/images/settings_appearance_more.png index 0e3e55cb..eae26cb9 100644 Binary files a/help/images/settings_appearance_more.png and b/help/images/settings_appearance_more.png differ diff --git a/help/images/settings_behavior.png b/help/images/settings_behavior.png index 220e6ed9..d706af1a 100644 Binary files a/help/images/settings_behavior.png and b/help/images/settings_behavior.png differ diff --git a/help/images/settings_console.png b/help/images/settings_console.png index 2d85a3d7..088cf1a7 100644 Binary files a/help/images/settings_console.png and b/help/images/settings_console.png differ diff --git a/help/images/settings_hotkeys.png b/help/images/settings_hotkeys.png index 1a7b1ecc..e7d101b2 100644 Binary files a/help/images/settings_hotkeys.png and b/help/images/settings_hotkeys.png differ diff --git a/help/images/settings_mouse.png b/help/images/settings_mouse.png index 13c26b89..2280f3a2 100644 Binary files a/help/images/settings_mouse.png and b/help/images/settings_mouse.png differ diff --git a/help/images/settings_tabs_background.png b/help/images/settings_tabs_background.png index 9e7d16b4..73699bb5 100644 Binary files a/help/images/settings_tabs_background.png and b/help/images/settings_tabs_background.png differ diff --git a/help/images/settings_tabs_main.png b/help/images/settings_tabs_main.png index 20097885..a7cea5ec 100644 Binary files a/help/images/settings_tabs_main.png and b/help/images/settings_tabs_main.png differ diff --git a/setup/config/console.xml b/setup/config/console.xml index 4f68589b..5c3e555c 100644 --- a/setup/config/console.xml +++ b/setup/config/console.xml @@ -1,6 +1,6 @@ - + @@ -24,16 +24,16 @@ - - - + + + - + @@ -51,6 +51,8 @@ + + @@ -65,7 +67,17 @@ + + + + + + + + + + @@ -78,6 +90,7 @@ + @@ -89,12 +102,12 @@ - - + + - + diff --git a/setup/console.iss b/setup/console.iss deleted file mode 100644 index 86a070d3..00000000 --- a/setup/console.iss +++ /dev/null @@ -1,61 +0,0 @@ -[Setup] -OutputDir=setup -SourceDir=..\ -OutputBaseFilename=Console 2.00 Beta b125 -VersionInfoVersion=2.00 -MinVersion=0,5.0.2195sp3 -AppName=Console -AppVerName=Console 2.00 Beta build 125 -DefaultDirName={pf}\Console -AllowNoIcons=true -ShowLanguageDialog=no -AppID={{99537A70-81BE-46EA-AA30-81C8F074AF45} -Compression=lzma -DefaultGroupName=Console -[Files] -; Binary files -Source: bin\release\Console.exe; DestDir: {app}; Components: main -Source: bin\release\ConsoleHook.dll; DestDir: {app}; Components: main -Source: help\console.chm; DestDir: {app}; Components: main -Source: setup\dlls\FreeImage.dll; DestDir: {app}; Components: main -Source: setup\dlls\FreeImagePlus.dll; DestDir: {app}; Components: main -Source: setup\dlls\msvcp71.dll; DestDir: {app}; Components: main -Source: setup\dlls\msvcr71.dll; DestDir: {app}; Components: main -; Config files -Source: setup\config\console.xml; DestDir: {app}; Components: main -; Fonts -Source: setup\fonts\FixedMedium5x7.fon; DestDir: {fonts}; FontInstall: FixedMedium5x7; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium5x8.fon; DestDir: {fonts}; FontInstall: FixedMedium5x8; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium6x9.fon; DestDir: {fonts}; FontInstall: FixedMedium6x9; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium6x10.fon; DestDir: {fonts}; FontInstall: FixedMedium6x10; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium6x12.fon; DestDir: {fonts}; FontInstall: FixedMedium6x12; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium6x13.fon; DestDir: {fonts}; FontInstall: FixedMedium6x13; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium7x13.fon; DestDir: {fonts}; FontInstall: FixedMedium7x13; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium7x14.fon; DestDir: {fonts}; FontInstall: FixedMedium7x14; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium8x13.fon; DestDir: {fonts}; FontInstall: FixedMedium8x13; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium9x15.fon; DestDir: {fonts}; FontInstall: FixedMedium9x15; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium9x18.fon; DestDir: {fonts}; FontInstall: FixedMedium9x18; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\FixedMedium10x20.fon; DestDir: {fonts}; FontInstall: FixedMedium10x20; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -Source: setup\fonts\TerminalMedium14.fon; DestDir: {fonts}; FontInstall: TerminalMedium14; Components: fonts; Flags: uninsrestartdelete fontisnttruetype -[Registry] -Root: HKCU; Subkey: Console\Console2 command window; ValueType: dword; ValueName: FontSize; ValueData: $000a0000; Flags: createvalueifdoesntexist uninsdeletekey; Components: main -Root: HKCU; Subkey: Console\Console2 command window; ValueType: dword; ValueName: FontFamily; ValueData: $00000036; Flags: createvalueifdoesntexist uninsclearvalue; Components: main -Root: HKCU; Subkey: Console\Console2 command window; ValueType: dword; ValueName: FontWeight; ValueData: $00000190; Flags: createvalueifdoesntexist uninsclearvalue; Components: main -Root: HKCU; Subkey: Console\Console2 command window; ValueType: string; ValueName: FaceName; ValueData: Lucida Console; Flags: createvalueifdoesntexist uninsclearvalue; Components: main -Root: HKLM; Subkey: SOFTWARE\Classes\Directory\shell\ConsoleHere; Tasks: console_here -Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\ConsoleHere; Tasks: console_here -Root: HKCR; Subkey: Directory\Shell\ConsoleHere; ValueType: string; ValueData: Co&nsole Here; Tasks: console_here -Root: HKCR; Subkey: Drive\Shell\ConsoleHere; ValueType: string; ValueData: Co&nsole Here; Tasks: console_here -Root: HKCR; Subkey: Directory\Shell\ConsoleHere\command; ValueType: string; ValueData: "{app}\console.exe -c ""/k cd /d """"%1"""""""; Tasks: console_here -Root: HKCR; Subkey: Drive\Shell\ConsoleHere\command; ValueType: string; ValueData: "{app}\console.exe -c ""/k cd /d """"%1"""""""; Tasks: console_here -[Icons] -Name: {group}\Console; Filename: {app}\Console.exe; WorkingDir: {app}; IconFilename: {app}\Console.exe; Comment: Console application; IconIndex: 0; Components: main -Name: {userdesktop}\Console; Filename: {app}\Console.exe; WorkingDir: {app}; IconFilename: {app}\Console.exe; Comment: Console application; IconIndex: 0; Components: main; Tasks: desktop_icon -Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Console; Filename: {app}\Console.exe; WorkingDir: {app}; IconFilename: {app}\Console.exe; Comment: Console application; IconIndex: 0; Components: main; Tasks: quicklaunch_icon -[Components] -Name: main; Description: Program files; Types: custom compact full; Flags: fixed -Name: fonts; Description: Install additional console fonts; Types: custom full -[Tasks] -Name: console_here; Description: "Install ""Console Here"" shell extension" -Name: desktop_icon; Description: Create desktop icon -Name: quicklaunch_icon; Description: Create Quick launch icon diff --git a/setup/dlls/FreeImage.dll b/setup/dlls/FreeImage.dll index 11145822..3ce0a708 100644 Binary files a/setup/dlls/FreeImage.dll and b/setup/dlls/FreeImage.dll differ diff --git a/setup/dlls/FreeImagePlus.dll b/setup/dlls/FreeImagePlus.dll index 103e9bc1..a19b8ef5 100644 Binary files a/setup/dlls/FreeImagePlus.dll and b/setup/dlls/FreeImagePlus.dll differ diff --git a/setup/dlls/x64/FreeImage.dll b/setup/dlls/x64/FreeImage.dll index a82ed5ab..0bf18d95 100644 Binary files a/setup/dlls/x64/FreeImage.dll and b/setup/dlls/x64/FreeImage.dll differ diff --git a/setup/dlls/x64/FreeImagePlus.dll b/setup/dlls/x64/FreeImagePlus.dll index f67f1d14..d24d3330 100644 Binary files a/setup/dlls/x64/FreeImagePlus.dll and b/setup/dlls/x64/FreeImagePlus.dll differ diff --git a/shared/Cpp11Helpers.h b/shared/Cpp11Helpers.h new file mode 100644 index 00000000..24934205 --- /dev/null +++ b/shared/Cpp11Helpers.h @@ -0,0 +1,46 @@ +#pragma once + +struct LocalFreeHelper +{ + void operator()(void * toFree) + { + ::LocalFree(static_cast(toFree)); + }; +}; + +struct CloseHandleHelper +{ + void operator()(void * toFree) + { + if( toFree && toFree != INVALID_HANDLE_VALUE ) + ::CloseHandle(static_cast(toFree)); + }; +}; + +#ifdef _INC_USERENV +struct DestroyEnvironmentBlockHelper +{ + void operator()(void * toFree) + { + if( toFree ) + ::DestroyEnvironmentBlock(toFree); + }; +}; +#endif + +struct FindCloseChangeNotificationHelper +{ + void operator()(void * toFree) + { + if( toFree != INVALID_HANDLE_VALUE ) + ::FindCloseChangeNotification(static_cast(toFree)); + }; +}; + +struct RegCloseKeyHelper +{ + void operator()(void * toFree) + { + ::RegCloseKey(static_cast(toFree)); + }; +}; \ No newline at end of file diff --git a/shared/SharedMemNames.h b/shared/SharedMemNames.h index bc3bf505..caa65553 100644 --- a/shared/SharedMemNames.h +++ b/shared/SharedMemNames.h @@ -6,15 +6,16 @@ class SharedMemNames { public: - static wformat formatConsoleParams; - static wformat formatInfo; - static wformat formatCursorInfo; - static wformat formatBuffer; - static wformat formatCopyInfo; - static wformat formatPasteInfo; - static wformat formatMouseEvent; - static wformat formatNewConsoleSize; - static wformat formatNewScrollPos; + static boost::wformat formatConsoleParams; + static boost::wformat formatInfo; + static boost::wformat formatCursorInfo; + static boost::wformat formatBuffer; + static boost::wformat formatCopyInfo; + static boost::wformat formatTextInfo; + static boost::wformat formatMouseEvent; + static boost::wformat formatNewConsoleSize; + static boost::wformat formatNewScrollPos; + static boost::wformat formatWatchdog; }; @@ -28,14 +29,15 @@ class SharedMemNames ////////////////////////////////////////////////////////////////////////////// -wformat SharedMemNames::formatConsoleParams(L"Console2_params_%1%"); -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::formatNewConsoleSize(L"Console2_newConsoleSize_%1%"); -wformat SharedMemNames::formatNewScrollPos(L"Console2_newScrollPos_%1%"); +boost::wformat SharedMemNames::formatConsoleParams(L"Console2_params_%1%"); +boost::wformat SharedMemNames::formatInfo(L"Console2_consoleInfo_%1%"); +boost::wformat SharedMemNames::formatCursorInfo(L"Console2_cursorInfo_%1%"); +boost::wformat SharedMemNames::formatBuffer(L"Console2_consoleBuffer_%1%"); +boost::wformat SharedMemNames::formatCopyInfo(L"Console2_consoleCopyInfo_%1%"); +boost::wformat SharedMemNames::formatTextInfo(L"Console2_consoleTextInfo_%1%"); +boost::wformat SharedMemNames::formatMouseEvent(L"Console2_consoleMouseEvent_%1%"); +boost::wformat SharedMemNames::formatNewConsoleSize(L"Console2_newConsoleSize_%1%"); +boost::wformat SharedMemNames::formatNewScrollPos(L"Console2_newScrollPos_%1%"); +boost::wformat SharedMemNames::formatWatchdog(L"Local\\Console2_parentProcessExit_%1%"); ////////////////////////////////////////////////////////////////////////////// diff --git a/shared/SharedMemory.h b/shared/SharedMemory.h index c84f84ba..20ef1c70 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,19 +48,19 @@ class SharedMemory private: - void CreateSyncObjects(SyncObjectTypes syncObjects, const wstring& strName); + void CreateSyncObjects(const std::shared_ptr& sa, SyncObjectTypes syncObjects, const wstring& strName); private: wstring m_strName; DWORD m_dwSize; - shared_ptr m_hSharedMem; - shared_ptr m_pSharedMem; + std::shared_ptr m_hSharedMem; + std::shared_ptr m_pSharedMem; - shared_ptr m_hSharedMutex; - shared_ptr m_hSharedReqEvent; - shared_ptr m_hSharedRespEvent; + std::shared_ptr m_hSharedMutex; + std::shared_ptr m_hSharedReqEvent; + std::shared_ptr m_hSharedRespEvent; }; ////////////////////////////////////////////////////////////////////////////// @@ -81,7 +84,7 @@ class SharedMemoryLock private: - shared_ptr m_lock; + std::shared_ptr m_lock; }; ////////////////////////////////////////////////////////////////////////////// @@ -144,24 +147,107 @@ 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; - m_hSharedMem = shared_ptr(::CreateFileMapping( + std::shared_ptr sa; + EXPLICIT_ACCESS ea[2]; + + SID_IDENTIFIER_AUTHORITY SIDAuthCreator = SECURITY_CREATOR_SID_AUTHORITY; + + PSID tmpSID = NULL; + std::shared_ptr creatorSID; // PSID + + PACL tmpACL = NULL; + std::shared_ptr acl; + + std::shared_ptr sd; // PSECURITY_DESCRIPTOR + + ::ZeroMemory(&ea, 2*sizeof(EXPLICIT_ACCESS)); + + if (strUser.length() > 0) + { + // 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)) + { + Win32Exception::ThrowFromLastError(); + } + + 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(); + + if (::SetEntriesInAcl(2, ea, NULL, &tmpACL) != ERROR_SUCCESS) + { + Win32Exception::ThrowFromLastError(); + } + + acl.reset(tmpACL, ::LocalFree); + + // initialize a security descriptor + sd.reset(::LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH), ::LocalFree); + if (!sd) + { + Win32Exception::ThrowFromLastError(); + } + + if (!::InitializeSecurityDescriptor(sd.get(), SECURITY_DESCRIPTOR_REVISION)) + { + Win32Exception::ThrowFromLastError(); + } + + // add the ACL to the security descriptor + if (!::SetSecurityDescriptorDacl( + sd.get(), + TRUE, // bDaclPresent flag + acl.get(), + FALSE)) // not a default DACL + { + Win32Exception::ThrowFromLastError(); + } + + // initialize a security attributes structure + sa.reset(new SECURITY_ATTRIBUTES); + sa->nLength = sizeof (SECURITY_ATTRIBUTES); + sa->lpSecurityDescriptor= sd.get(); + sa->bInheritHandle = FALSE; + } + + m_hSharedMem = std::shared_ptr(::CreateFileMapping( INVALID_HANDLE_VALUE, - NULL, + sa.get(), PAGE_READWRITE, 0, m_dwSize * sizeof(T), m_strName.c_str()), ::CloseHandle); - // TODO: error handling - //if (m_hSharedMem.get() == NULL) return false; + if (!m_hSharedMem) Win32Exception::ThrowFromLastError(); - m_pSharedMem = shared_ptr(static_cast(::MapViewOfFile( + m_pSharedMem = std::shared_ptr(static_cast(::MapViewOfFile( m_hSharedMem.get(), FILE_MAP_ALL_ACCESS, 0, @@ -169,11 +255,11 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp 0)), ::UnmapViewOfFile); - ::ZeroMemory(m_pSharedMem.get(), m_dwSize * sizeof(T)); + if (!m_pSharedMem) Win32Exception::ThrowFromLastError(); - if (syncObjects > syncObjNone) CreateSyncObjects(syncObjects, strName); + ::ZeroMemory(m_pSharedMem.get(), m_dwSize * sizeof(T)); - //if (m_pSharedMem.get() == NULL) return false; + if (syncObjects > syncObjNone) CreateSyncObjects(sa, syncObjects, strName); } ////////////////////////////////////////////////////////////////////////////// @@ -186,16 +272,20 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) { m_strName = strName; - m_hSharedMem = shared_ptr(::OpenFileMapping( + m_hSharedMem = std::shared_ptr(::OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, m_strName.c_str()), ::CloseHandle); - // TODO: error handling - //if (m_hSharedMem.get() == NULL) return false; + if (!m_hSharedMem || (m_hSharedMem.get() == INVALID_HANDLE_VALUE)) + { + DWORD dwLastError = ::GetLastError(); + OutputDebugString(str(boost::wformat(L"Error opening shared mem %1%, error: %2%\n") % m_strName % dwLastError).c_str()); + Win32Exception::Throw(dwLastError); + } - m_pSharedMem = shared_ptr(static_cast(::MapViewOfFile( + m_pSharedMem = std::shared_ptr(static_cast(::MapViewOfFile( m_hSharedMem.get(), FILE_MAP_ALL_ACCESS, 0, @@ -203,9 +293,14 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) 0)), ::UnmapViewOfFile); - if (syncObjects > syncObjNone) CreateSyncObjects(syncObjects, strName); + if (!m_pSharedMem) + { + DWORD dwLastError = ::GetLastError(); + OutputDebugString(str(boost::wformat(L"Error mapping shared mem %1%, error: %2%\n") % m_strName % dwLastError).c_str()); + Win32Exception::Throw(dwLastError); + } - //if (m_pSharedMem.get() == NULL) return false; + if (syncObjects > syncObjNone) CreateSyncObjects(std::shared_ptr(), syncObjects, strName); } ////////////////////////////////////////////////////////////////////////////// @@ -216,7 +311,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 +323,7 @@ void SharedMemory::Lock() template void SharedMemory::Release() { - if (m_hSharedMutex.get() == NULL) return; + if (!m_hSharedMutex) return; ::ReleaseMutex(m_hSharedMutex.get()); } @@ -240,8 +335,16 @@ void SharedMemory::Release() template void SharedMemory::SetReqEvent() { - if (m_hSharedReqEvent.get() == NULL) return; - ::SetEvent(m_hSharedReqEvent.get()); + if (!m_hSharedReqEvent) + { + OutputDebugString(str(boost::wformat(L"Req Event %1% is null!") % m_strName).c_str()); + return; + } + + if (!::SetEvent(m_hSharedReqEvent.get())) + { + OutputDebugString(str(boost::wformat(L"SetEvent %1% failed: %2%!\n") % m_strName % ::GetLastError()).c_str()); + } } ////////////////////////////////////////////////////////////////////////////// @@ -252,7 +355,11 @@ void SharedMemory::SetReqEvent() template void SharedMemory::SetRespEvent() { - if (m_hSharedRespEvent.get() == NULL) return; + if (!m_hSharedRespEvent) + { + OutputDebugString(str(boost::wformat(L"Resp Event %1% is null!") % m_strName).c_str()); + return; + } ::SetEvent(m_hSharedRespEvent.get()); } @@ -345,24 +452,36 @@ SharedMemory& SharedMemory::operator=(const T& val) ////////////////////////////////////////////////////////////////////////////// template -void SharedMemory::CreateSyncObjects(SyncObjectTypes syncObjects, const wstring& strName) +void SharedMemory::CreateSyncObjects(const std::shared_ptr& sa, SyncObjectTypes syncObjects, const wstring& strName) { if (syncObjects >= syncObjRequest) { - m_hSharedMutex = shared_ptr( - ::CreateMutex(NULL, FALSE, (strName + wstring(L"_mutex")).c_str()), + m_hSharedMutex = std::shared_ptr( + ::CreateMutex(sa.get(), FALSE, (wstring(L"") + strName + wstring(L"_mutex")).c_str()), ::CloseHandle); - m_hSharedReqEvent = shared_ptr( - ::CreateEvent(NULL, FALSE, FALSE, (strName + wstring(L"_req_event")).c_str()), + if( !m_hSharedMutex ) Win32Exception::ThrowFromLastError(); + + OutputDebugString(str(boost::wformat(L"m_hSharedMutex %1%: %2%\n") % m_strName % (DWORD)(m_hSharedMutex.get())).c_str()); + + m_hSharedReqEvent = std::shared_ptr( + ::CreateEvent(sa.get(), FALSE, FALSE, (wstring(L"") + strName + wstring(L"_req_event")).c_str()), ::CloseHandle); + + if( !m_hSharedReqEvent ) Win32Exception::ThrowFromLastError(); + + OutputDebugString(str(boost::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()), + m_hSharedRespEvent = std::shared_ptr( + ::CreateEvent(sa.get(), FALSE, FALSE, (wstring(L"") + strName + wstring(L"_resp_event")).c_str()), ::CloseHandle); + + if( !m_hSharedRespEvent ) Win32Exception::ThrowFromLastError(); + + OutputDebugString(str(boost::wformat(L"m_hSharedRespEvent %1%: %2%\n") % m_strName % (DWORD)(m_hSharedRespEvent.get())).c_str()); } } diff --git a/shared/Structures.h b/shared/Structures.h index 126cd496..69963d76 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; }; @@ -109,7 +115,11 @@ struct ConsoleCopy , bNoWrap(false) , bTrimSpaces(false) , copyNewlineChar(newlineCRLF) + , bBold(false) + , bItalic(false) + , dwSize(24) { + szFontName[0] = 0; } COORD coordStart; @@ -117,6 +127,11 @@ struct ConsoleCopy bool bNoWrap; bool bTrimSpaces; CopyNewlineChar copyNewlineChar; + bool bBold; + bool bItalic; + DWORD dwSize; + char szFontName [256]; + COLORREF consoleColors[16]; }; @@ -128,6 +143,28 @@ struct ConsoleCopy ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +struct ConsoleInfo +{ + ConsoleInfo() + : csbi() + , textChanged(false) + { + } + + CONSOLE_SCREEN_BUFFER_INFO csbi; + bool textChanged; +}; + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// struct CharInfo @@ -142,9 +179,49 @@ 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; }; ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +struct TextInfo +{ + TextInfo() + : padding(0) + { + } + + union + { + UINT_PTR mem; + // padding for 32-bit processes started from 64-bit Console + __int64 padding; + }; +}; + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// diff --git a/shared/Win32Exception.h b/shared/Win32Exception.h new file mode 100644 index 00000000..43e596c2 --- /dev/null +++ b/shared/Win32Exception.h @@ -0,0 +1,43 @@ +#pragma once + +class Win32Exception : public std::exception +{ + DWORD errorCode_; + mutable std::string buff_; + + void FormatMessage() const + { + LPSTR buffer = nullptr; + DWORD bufferLength = ::FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + GetErrorCode(), + 0, + reinterpret_cast(&buffer), + 0, + NULL); + if( bufferLength ) + { + std::unique_ptr buffPtr(buffer); + buff_ = buffer; + } + } + +public: + Win32Exception(DWORD errorCode) : errorCode_(errorCode) {}; + + static void Throw(DWORD lastError) { throw Win32Exception(lastError); } + + static void ThrowFromLastError() { Throw(::GetLastError()); }; + + inline DWORD GetErrorCode() const + { + return errorCode_; + } + + virtual const char* what() const + { + FormatMessage(); + return buff_.c_str(); + }; +}; diff --git a/shared/version.h b/shared/version.h new file mode 100644 index 00000000..600f6ed1 --- /dev/null +++ b/shared/version.h @@ -0,0 +1,9 @@ +#pragma once + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 5 +#define VERSION_BUILD 0 +#define VERSION_BUILD2 13033 +#define VERSION_FILE "1.5.0" +#define VERSION_PRODUCT "1, 5, 0, 13033" +#define VERSION_COPYRIGHT "Copyright © 2011-2013 Bucher Christophe" 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..504bc53a --- /dev/null +++ b/wtl/wtl/include/atlapp.h @@ -0,0 +1,2125 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 WTL 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 + +#if (_ATL_VER >= 0x0900) && defined(_ATL_MIN_CRT) + #error _ATL_MIN_CRT is not supported with ATL 9.0 and higher +#endif + +#if defined(_WIN32_WCE) && defined(_ATL_MIN_CRT) + #pragma message("Warning: WTL for Windows CE doesn't use _ATL_MIN_CRT") +#endif + +#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 + +#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) + +#if (_ATL_VER >= 0x0900) && !defined(_SECURE_ATL) + #define _SECURE_ATL 1 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// WTL version number + +#define _WTL_VER 0x0810 + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CMessageFilter +// CIdleHandler +// CMessageLoop +// +// CAppModule +// CServerAppModule +// +// CRegKeyEx +// +// Global functions: +// AtlGetDefaultGuiFont() +// AtlCreateControlFont() +// 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 and ATL11 fix +#if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE) + namespace ATL { HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); }; +#endif + +#ifndef WM_MOUSEHWHEEL + #define WM_MOUSEHWHEEL 0x020E +#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 - "MS Shell Dlg" stock font +inline HFONT AtlGetDefaultGuiFont() +{ +#ifndef _WIN32_WCE + return (HFONT)::GetStockObject(DEFAULT_GUI_FONT); +#else // CE specific + return (HFONT)::GetStockObject(SYSTEM_FONT); +#endif // _WIN32_WCE +} + +// Control font helper - default font for controls not in a dialog +// (NOTE: Caller owns the font, and should destroy it when it's no longer needed) +inline HFONT AtlCreateControlFont() +{ +#ifndef _WIN32_WCE + LOGFONT lf = { 0 }; + ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); + HFONT hFont = ::CreateFontIndirect(&lf); + ATLASSERT(hFont != NULL); + return hFont; +#else // CE specific + return (HFONT)::GetStockObject(SYSTEM_FONT); +#endif // _WIN32_WCE +} + +// Bold font helper +// (NOTE: Caller owns the font, and should destroy it when it's no longer needed) +inline HFONT AtlCreateBoldFont(HFONT hFont = NULL) +{ + LOGFONT lf = { 0 }; +#ifndef _WIN32_WCE + if(hFont == NULL) + ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); + else + ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)); +#else // CE specific + if(hFont == NULL) + hFont = (HFONT)::GetStockObject(SYSTEM_FONT); + ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)); +#endif // _WIN32_WCE + lf.lfWeight = FW_BOLD; + HFONT hFontBold = ::CreateFontIndirect(&lf); + ATLASSERT(hFontBold != NULL); + 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)); + } + + inline bool IsThemeAvailable() + { + bool bRet = false; + + if(IsCommCtrl6()) + { + 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); + bRet = (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE); + if(bRet) + { + typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)(); + PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed"); + ATLASSERT(pfnIsAppThemed != NULL); + bRet = (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE); + } + + ::FreeLibrary(hThemeDLL); + } + } + + return bRet; + } + + inline bool IsWin7() + { + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + BOOL bRet = ::GetVersionEx(&ovi); + return ((bRet != FALSE) && (ovi.dwMajorVersion == 6) && (ovi.dwMinorVersion >= 1)); + } + + inline bool IsRibbonUIAvailable() + { + static INT iRibbonUI = -1; + +#if defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7) + if (iRibbonUI == -1) + { + HMODULE hRibbonDLL = ::LoadLibrary(_T("propsys.dll")); + if (hRibbonDLL != NULL) + { + const GUID CLSID_UIRibbonFramework = { 0x926749fa, 0x2615, 0x4987, { 0x88, 0x45, 0xc3, 0x3e, 0x65, 0xf2, 0xb9, 0x57 } }; + // block - create instance + { + ATL::CComPtr pIUIFramework; + iRibbonUI = SUCCEEDED(pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework)) ? 1 : 0; + } + ::FreeLibrary(hRibbonDLL); + } + else + { + iRibbonUI = 0; + } + } +#endif // defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7) + + return (iRibbonUI == 1); + } + +#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 +#pragma warning(disable: 4996) + return _vstprintf(lpstrBuff, lpstrFormat, args); +#pragma warning(default: 4996) +#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 + + +/////////////////////////////////////////////////////////////////////////////// +// MinCrtHelper - helper functions for using _ATL_MIN_CRT + +namespace MinCrtHelper +{ + inline int _isspace(TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _istspace(ch); +#else // _ATL_MIN_CRT + WORD type = 0; + ::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); + return (type & C1_SPACE) == C1_SPACE; +#endif // _ATL_MIN_CRT + } + + inline int _isdigit(TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _istdigit(ch); +#else // _ATL_MIN_CRT + WORD type = 0; + ::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); + return (type & C1_DIGIT) == C1_DIGIT; +#endif // _ATL_MIN_CRT + } + + inline int _atoi(LPCTSTR str) + { +#ifndef _ATL_MIN_CRT + return _ttoi(str); +#else // _ATL_MIN_CRT + while(_isspace(*str) != 0) + ++str; + + TCHAR ch = *str++; + TCHAR sign = ch; // save sign indication + if(ch == _T('-') || ch == _T('+')) + ch = *str++; // skip sign + + int total = 0; + while(_isdigit(ch) != 0) + { + total = 10 * total + (ch - '0'); // accumulate digit + ch = *str++; // get next char + } + + return (sign == '-') ? -total : total; // return result, negated if necessary +#endif // _ATL_MIN_CRT + } + + inline LPCTSTR _strrchr(LPCTSTR str, TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _tcsrchr(str, ch); +#else // _ATL_MIN_CRT + LPCTSTR lpsz = NULL; + while(*str != 0) + { + if(*str == ch) + lpsz = str; + str = ::CharNext(str); + } + return lpsz; +#endif // _ATL_MIN_CRT + } + + inline LPTSTR _strrchr(LPTSTR str, TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _tcsrchr(str, ch); +#else // _ATL_MIN_CRT + LPTSTR lpsz = NULL; + while(*str != 0) + { + if(*str == ch) + lpsz = str; + str = ::CharNext(str); + } + return lpsz; +#endif // _ATL_MIN_CRT + } +}; // namespace MinCrtHelper + + +/////////////////////////////////////////////////////////////////////////////// +// 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) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CRegKeyEx - adds type-specific methods to ATL3 CRegKey + +#if (_ATL_VER < 0x0700) + +class CRegKeyEx : public ATL::CRegKey +{ +public: +// Constructors and operators + CRegKeyEx(HKEY hKey = NULL) + { + m_hKey = hKey; + } + + CRegKeyEx(CRegKeyEx& key) + { + Attach(key.Detach()); + } + + CRegKeyEx& operator =(CRegKeyEx& key) + { + Close(); + Attach(key.Detach()); + return *this; + } + +// Methods + LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast(pValue), nBytes); + } + + LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) + { + ATLASSERT(m_hKey != NULL); + + OLECHAR szGUID[64] = { 0 }; + ::StringFromGUID2(guidValue, szGUID, 64); + + USES_CONVERSION; + LPCTSTR lpstr = OLE2CT(szGUID); +#ifndef _UNICODE + if(lpstr == NULL) + return E_OUTOFMEMORY; +#endif + return SetStringValue(pszValueName, lpstr); + } + + LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_BINARY, reinterpret_cast(pValue), nBytes); + } + + LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast(&dwValue), sizeof(DWORD)); + } + +#ifndef _WIN32_WCE + LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_QWORD, reinterpret_cast(&qwValue), sizeof(ULONGLONG)); + } +#endif + + LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) + { + ATLASSERT(m_hKey != NULL); + if(pszValue == NULL) + { + ATLASSERT(FALSE); + return ERROR_INVALID_DATA; + } + ATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)); + + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast(pszValue), (lstrlen(pszValue) + 1) * sizeof(TCHAR)); + } + + LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) + { + ATLASSERT(m_hKey != NULL); + if(pszValue == NULL) + { + ATLASSERT(FALSE); + return ERROR_INVALID_DATA; + } + + ULONG nBytes = 0; + ULONG nLength = 0; + LPCTSTR pszTemp = pszValue; + do + { + nLength = lstrlen(pszTemp) + 1; + pszTemp += nLength; + nBytes += nLength * sizeof(TCHAR); + } while (nLength != 1); + + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast(pszValue), nBytes); + } + + LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) + { + ATLASSERT(m_hKey != NULL); + return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast(pData), pnBytes); + } + + LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) + { + ATLASSERT(m_hKey != NULL); + + guidValue = GUID_NULL; + + TCHAR szGUID[64] = { 0 }; + ULONG nCount = 64; + LONG lRes = QueryStringValue(pszValueName, szGUID, &nCount); + + if (lRes != ERROR_SUCCESS) + return lRes; + + if(szGUID[0] != _T('{')) + return ERROR_INVALID_DATA; + + USES_CONVERSION; + LPOLESTR lpstr = T2OLE(szGUID); +#ifndef _UNICODE + if(lpstr == NULL) + return E_OUTOFMEMORY; +#endif + + HRESULT hr = ::CLSIDFromString(lpstr, &guidValue); + if (FAILED(hr)) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + + LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) + { + ATLASSERT(pnBytes != NULL); + ATLASSERT(m_hKey != NULL); + + DWORD dwType = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pValue), pnBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_BINARY) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + + LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) + { + ATLASSERT(m_hKey != NULL); + + ULONG nBytes = sizeof(DWORD); + DWORD dwType = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&dwValue), &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_DWORD) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + + LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) + { + ATLASSERT(m_hKey != NULL); + + ULONG nBytes = sizeof(ULONGLONG); + DWORD dwType = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&qwValue), &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_QWORD) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + + LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) + { + ATLASSERT(m_hKey != NULL); + ATLASSERT(pnChars != NULL); + + ULONG nBytes = (*pnChars) * sizeof(TCHAR); + DWORD dwType = 0; + *pnChars = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), &nBytes); + + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + + if(dwType != REG_SZ && dwType != REG_EXPAND_SZ) + { + return ERROR_INVALID_DATA; + } + + if (pszValue != NULL) + { + if(nBytes != 0) + { + if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0)) + return ERROR_INVALID_DATA; + } + else + { + pszValue[0] = _T('\0'); + } + } + + *pnChars = nBytes / sizeof(TCHAR); + + return ERROR_SUCCESS; + } + + LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) + { + ATLASSERT(m_hKey != NULL); + ATLASSERT(pnChars != NULL); + + if (pszValue != NULL && *pnChars < 2) + return ERROR_INSUFFICIENT_BUFFER; + + ULONG nBytes = (*pnChars) * sizeof(TCHAR); + DWORD dwType = 0; + *pnChars = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_MULTI_SZ) + return ERROR_INVALID_DATA; + if (pszValue != NULL && (nBytes % sizeof(TCHAR) != 0 || nBytes / sizeof(TCHAR) < 1 || pszValue[nBytes / sizeof(TCHAR) - 1] != 0 || ((nBytes / sizeof(TCHAR)) > 1 && pszValue[nBytes / sizeof(TCHAR) - 2] != 0))) + return ERROR_INVALID_DATA; + + *pnChars = nBytes / sizeof(TCHAR); + + return ERROR_SUCCESS; + } +}; + +#else // !(_ATL_VER < 0x0700) + +typedef ATL::CRegKey CRegKeyEx; + +#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 +// (ATL3: excluded from atlbase.h if _ATL_DLL is defined; ATL11: removed) + +#if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !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..d488c1aa --- /dev/null +++ b/wtl/wtl/include/atlcrack.h @@ -0,0 +1,2384 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 + +#ifndef __ATLAPP_H__ + #error atlcrack.h requires atlapp.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// 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(CRgnHandle 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, CPoint point) +#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(CMenuHandle menu) +#define MSG_WM_INITMENU(func) \ + if (uMsg == WM_INITMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((HMENU)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInitMenuPopup(CMenuHandle 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, CMenuHandle 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, CMenuHandle 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(CFontHandle 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, CMenuHandle 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, CMenuHandle 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, CMenuHandle 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, CMenuHandle 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..67155657 --- /dev/null +++ b/wtl/wtl/include/atlctrls.h @@ -0,0 +1,10035 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 + +#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) + + // Note: selects only one item + BOOL SelectItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + + // multi-selection only: de-select all items + if((GetStyle() & LVS_SINGLESEL) == 0) + SetItemState(-1, 0, LVIS_SELECTED); + + 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..7f95bdfd --- /dev/null +++ b/wtl/wtl/include/atlctrlw.h @@ -0,0 +1,4157 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 + +#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 + CClientDC dc(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + 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, dc, dcMem); + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.Add(hBitmap); + } + } + + void _AddVistaBitmapFromImageList(int nIndex) + { + // Create display compatible memory DC + CClientDC dc(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + // Create bitmap for menu item + T* pT = static_cast(this); + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, 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 + CClientDC dc(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + // Create bitmap for menu item + T* pT = static_cast(this); + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, 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..4189ea8d --- /dev/null +++ b/wtl/wtl/include/atlctrlx.h @@ -0,0 +1,4979 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 +#define HLINK_AUTOCREATELINKFONT 0x00000080 +#define HLINK_SINGLELINE 0x00000100 + +// 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_hFontLink; + 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; + bool m_bInternalNormalFont:1; + + +// Constructor/Destructor + CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) : + m_lpstrLabel(NULL), m_lpstrHyperLink(NULL), + m_hCursor(NULL), m_hFontLink(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), m_bInternalNormalFont(false) + { + ::SetRectEmpty(&m_rcLink); + } + + ~CHyperLinkImpl() + { + delete [] m_lpstrLabel; + delete [] m_lpstrHyperLink; +#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_hFontLink; + } + + void SetLinkFont(HFONT hFont) + { + if(m_bInternalLinkFont) + { + ::DeleteObject(m_hFontLink); + m_bInternalLinkFont = false; + } + + m_hFontLink = hFont; + + T* pT = static_cast(this); + pT->CalcLabelRect(); + } + + int GetIdealHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return -1; + if(!m_bPaintLabel) + return -1; + + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + 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 | uFormat | DT_CALCRECT); + dc.SelectFont(m_hFontLink); + RECT rcLink = rect; + dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | uFormat | 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 + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + RECT rcLeft = rcClient; + dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(m_hFontLink); + RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(m_hFontNormal); + RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | 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_hFontLink != NULL) + hOldFont = dc.SelectFont(m_hFontLink); + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + DWORD dwStyle = GetStyle(); + UINT uFormat = DT_LEFT; + if (dwStyle & SS_CENTER) + uFormat = DT_CENTER; + else if (dwStyle & SS_RIGHT) + uFormat = DT_RIGHT; + uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + dc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT); + if(m_hFontLink != 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(m_hFontNormal == NULL) + m_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); +#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; + } + + void CreateLinkFontFromNormal() + { + if(m_bInternalLinkFont) + { + ::DeleteObject(m_hFontLink); + m_bInternalLinkFont = false; + } + + CFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT); + LOGFONT lf = { 0 }; + font.GetLogFont(&lf); + + if(IsUsingTagsBold()) + lf.lfWeight = FW_BOLD; + else if(!IsNotUnderlined()) + lf.lfUnderline = TRUE; + + m_hFontLink = ::CreateFontIndirect(&lf); + m_bInternalLinkFont = true; + ATLASSERT(m_hFontLink != NULL); + } + +// 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; + } + + if(m_bInternalLinkFont) + { + ::DeleteObject(m_hFontLink); + m_hFontLink = NULL; + m_bInternalLinkFont = false; + } + + if(m_bInternalNormalFont) + { + ::DeleteObject(m_hFontNormal); + m_hFontNormal = NULL; + m_bInternalNormalFont = false; + } + + 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*/) + { + if(m_bInternalNormalFont) + { + ::DeleteObject(m_hFontNormal); + m_bInternalNormalFont = false; + } + + bool bCreateLinkFont = m_bInternalLinkFont; + + m_hFontNormal = (HFONT)wParam; + + if(bCreateLinkFont || IsAutoCreateLinkFont()) + CreateLinkFontFromNormal(); + + T* pT = static_cast(this); + pT->CalcLabelRect(); + + 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 fonts + if(m_bPaintLabel) + { + if(m_hFontNormal == NULL) + { + m_hFontNormal = AtlCreateControlFont(); + m_bInternalNormalFont = true; + } + + if(m_hFontLink == NULL) + CreateLinkFontFromNormal(); + } + +#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) + { + ATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]); + if(m_lpstrLabel != NULL) + ATLVERIFY(GetWindowText(m_lpstrLabel, nLen + 1) > 0); + } + } + + 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) + { + CRegKeyEx rk; + LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings")); + if(lRet == ERROR_SUCCESS) + { + const int cchValue = 12; + TCHAR szValue[cchValue] = { 0 }; + ULONG ulCount = cchValue; + lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount); + if(lRet == ERROR_SUCCESS) + { + COLORREF clr = pT->_ParseColorString(szValue); + ATLASSERT(clr != CLR_INVALID); + if(clr != CLR_INVALID) + m_clrLink = clr; + } + + ulCount = cchValue; + lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount); + if(lRet == ERROR_SUCCESS) + { + 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] = MinCrtHelper::_atoi(lpstr); + lpstr = &p[1]; + break; + } + } + if(c[i] == -1) + return CLR_INVALID; + } + if(*lpstr == _T('\0')) + return CLR_INVALID; + c[2] = MinCrtHelper::_atoi(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); + + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + RECT rcLeft = rcClient; + if(lpstrLeft != NULL) + dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(m_hFontLink); + RECT rcLink = rcClient; + if(lpstrLeft != NULL) + rcLink.left = rcLeft.right; + dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(hFontOld); + + m_rcLink = rcLink; + } + else + { + HFONT hOldFont = NULL; + if(m_hFontLink != NULL) + hOldFont = dc.SelectFont(m_hFontLink); + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + DWORD dwStyle = GetStyle(); + UINT uFormat = DT_LEFT; + if (dwStyle & SS_CENTER) + uFormat = DT_CENTER; + else if (dwStyle & SS_RIGHT) + uFormat = DT_RIGHT; + uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + dc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT); + if(m_hFontLink != 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); + + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + if(lpstrLeft != NULL) + dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat); + + COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); + if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) + dc.SelectFont(m_hFontLink); + else + dc.SelectFont(m_hFontNormal); + + dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat); + + 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 | uFormat); + } + + 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_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) + hFontOld = dc.SelectFont(m_hFontLink); + else + hFontOld = dc.SelectFont(m_hFontNormal); + + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + + DWORD dwStyle = GetStyle(); + UINT uFormat = DT_LEFT; + if (dwStyle & SS_CENTER) + uFormat = DT_CENTER; + else if (dwStyle & SS_RIGHT) + uFormat = DT_RIGHT; + uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + dc.DrawText(lpstrText, -1, &m_rcLink, uFormat); + + 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); + } + + bool IsAutoCreateLinkFont() const + { + return ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT); + } + + bool IsSingleLine() const + { + return ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE); + } +}; + +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 + HFONT m_hFont; + bool m_bInternalFont; + + +// Constructor + CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL), m_bInternalFont(false) + { + 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_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_GETFONT, OnGetFont) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + 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*/) + { + if(m_hFont == NULL) + { + // The same as AtlCreateControlFont() for horizontal pane +#ifndef _WIN32_WCE + LOGFONT lf = { 0 }; + ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); + if(IsVertical()) + lf.lfEscapement = 900; // 90 degrees + m_hFont = ::CreateFontIndirect(&lf); +#else // CE specific + m_hFont = (HFONT)::GetStockObject(SYSTEM_FONT); + if(IsVertical()) + { + CLogFont lf(m_hFont); + lf.lfEscapement = 900; // 90 degrees + m_hFont = ::CreateFontIndirect(&lf); + } +#endif // _WIN32_WCE + m_bInternalFont = true; + } + + T* pT = static_cast(this); + pT->CalcSize(); + + if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0) + pT->CreateCloseButton(); + + return 0; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_bInternalFont) + { + ::DeleteObject(m_hFont); + m_hFont = NULL; + m_bInternalFont = false; + } + + 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 OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hFont; + } + + LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_bInternalFont) + { + ::DeleteObject(m_hFont); + m_bInternalFont = false; + } + + m_hFont = (HFONT)wParam; + + T* pT = static_cast(this); + pT->CalcSize(); + + if((BOOL)lParam != FALSE) + pT->UpdateLayout(); + + 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(); + if(font.IsNull()) + font = (HFONT)::GetStockObject(SYSTEM_FONT); + 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 m_hFont; + } + +#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); + + // draw title text + dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); + dc.SetBkMode(TRANSPARENT); + T* pT = static_cast(this); + HFONT hFontOld = dc.SelectFont(pT->GetTitleFont()); +#ifdef _WIN32_WCE + const UINT DT_END_ELLIPSIS = 0; +#endif // _WIN32_WCE + + if(IsVertical()) + { + rect.top += m_cxyTextOffset; + rect.bottom -= m_cxyTextOffset; + if(m_tb.m_hWnd != NULL) + rect.top += m_cxToolBar;; + + RECT rcCalc = { rect.left, rect.bottom, rect.right, rect.top }; + int cxFont = dc.DrawText(m_szTitle, -1, &rcCalc, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT); + RECT rcText = { 0 }; + rcText.left = (rect.right - rect.left - cxFont) / 2; + rcText.right = rcText.left + (rect.bottom - rect.top); + rcText.top = rect.bottom; + rcText.bottom = rect.top; + dc.DrawText(m_szTitle, -1, &rcText, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS); + } + else + { + rect.left += m_cxyTextOffset; + rect.right -= m_cxyTextOffset; + if(m_tb.m_hWnd != NULL) + rect.right -= m_cxToolBar;; + + dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); + } + + 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; + bool m_bNoTabDrag:1; + // internal + bool m_bTabCapture:1; + bool m_bTabDrag:1; + bool m_bInternalFont: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_bNoTabDrag(false), + m_bTabCapture(false), + m_bTabDrag(false), + m_bInternalFont(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) + MESSAGE_HANDLER(WM_GETFONT, OnGetFont) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + 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(); + } + + if(m_bInternalFont) + { + HFONT hFont = m_tab.GetFont(); + m_tab.SetFont(NULL, FALSE); + ::DeleteObject(hFont); + m_bInternalFont = false; + } + + 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 OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return m_tab.SendMessage(WM_GETFONT); + } + + LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_bInternalFont) + { + HFONT hFont = m_tab.GetFont(); + m_tab.SetFont(NULL, FALSE); + ::DeleteObject(hFont); + m_bInternalFont = false; + } + + m_tab.SendMessage(WM_SETFONT, wParam, lParam); + + T* pT = static_cast(this); + m_cyTabHeight = pT->CalcTabHeight(); + + if((BOOL)lParam != FALSE) + pT->UpdateLayout(); + + 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_bNoTabDrag && (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(AtlCreateControlFont()); + m_bInternalFont = true; + + 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..cc4e3bcd --- /dev/null +++ b/wtl/wtl/include/atlddx.h @@ -0,0 +1,685 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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; \ + } + +// DDX support for Tab, Combo, ListBox and ListView selection index +// Note: Specialized versions require atlctrls.h to be included first +#if (_MSC_VER >= 1300) + +#define DDX_INDEX(CtrlClass, nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Index(nID, var, bSaveAndValidate); + +#ifdef __ATLCTRLS_H__ + #define DDX_TAB_INDEX(nID, var) DDX_INDEX(WTL::CTabCtrl, nID, var) + #define DDX_COMBO_INDEX(nID, var) DDX_INDEX(WTL::CComboBox, nID, var) + #define DDX_LISTBOX_INDEX(nID, var) DDX_INDEX(WTL::CListBox, nID, var) + #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var) +#endif // __ATLCTRLS_H__ + +#endif // (_MSC_VER >= 1300) + + +/////////////////////////////////////////////////////////////////////////////// +// 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)); + } + +// DDX support for Tab, Combo, ListBox and ListView selection index +#if (_MSC_VER >= 1300) + template + INT _getSel(TCtrl& tCtrl) + { + return tCtrl.GetCurSel(); + } + + template + void _setSel(TCtrl& tCtrl, INT iSel) + { + if(iSel < 0) + tCtrl.SetCurSel(-1); + else + tCtrl.SetCurSel(iSel); + } + +#ifdef __ATLCTRLS_H__ + // ListViewCtrl specialization + template <> + INT _getSel(WTL::CListViewCtrl& tCtrl) + { + return tCtrl.GetSelectedIndex(); + } + + template <> + void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel) + { + if(iSel < 0) + tCtrl.SelectItem(-1); + else + tCtrl.SelectItem(iSel); + } +#endif // __ATLCTRLS_H__ + + template + void DDX_Index(UINT nID, INT& nVal, BOOL bSave) + { + T* pT = static_cast(this); + TCtrl ctrl(pT->GetDlgItem(nID)); + + if(bSave) + nVal = _getSel(ctrl); + else + _setSel(ctrl, nVal); + } +#endif // (_MSC_VER >= 1300) + +// 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..421694e5 --- /dev/null +++ b/wtl/wtl/include/atldlgs.h @@ -0,0 +1,6386 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 +// +// CDialogBaseUnits +// 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; + +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + m_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME); +#else + m_ofn.lStructSize = sizeof(m_ofn); +#endif + +#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 = MinCrtHelper::_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 = MinCrtHelper::_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 (MinCrtHelper::_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)); + } +}; + +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, 0, (LPARAM)lpstr); + } + + 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 + + +///////////////////////////////////////////////////////////////////////// +// CDialogBaseUnits - Dialog Units helper +// + +class CDialogBaseUnits +{ +public: + SIZE m_sizeUnits; + +// Constructors + CDialogBaseUnits() + { + // The base units of the out-dated System Font + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + + CDialogBaseUnits(HWND hWnd) + { + if(!InitDialogBaseUnits(hWnd)) { + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + } + + CDialogBaseUnits(HFONT hFont, HWND hWnd = NULL) + { + if(!InitDialogBaseUnits(hFont, hWnd)) { + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + } + + CDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL) + { + if(!InitDialogBaseUnits(lf, hWnd)) { + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + } + +// Operations + BOOL InitDialogBaseUnits(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + RECT rc = { 0, 0, 4, 8 }; + if(!::MapDialogRect(hWnd, &rc)) return FALSE; + m_sizeUnits.cx = rc.right; + m_sizeUnits.cy = rc.bottom; + return TRUE; + } + + BOOL InitDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL) + { + CFont font; + font.CreateFontIndirect(&lf); + if(font.IsNull()) return FALSE; + return InitDialogBaseUnits(font, hWnd); + } + + BOOL InitDialogBaseUnits(HFONT hFont, HWND hWnd = NULL) + { + ATLASSERT(hFont != NULL); + CWindowDC dc = hWnd; + TEXTMETRIC tmText = { 0 }; + SIZE sizeText = { 0 }; + HFONT hFontOld = dc.SelectFont(hFont); + dc.GetTextMetrics(&tmText); + m_sizeUnits.cy = tmText.tmHeight + tmText.tmExternalLeading; + dc.GetTextExtent(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &sizeText); + m_sizeUnits.cx = (sizeText.cx + 26) / 52; + dc.SelectFont(hFontOld); + return TRUE; + } + + SIZE GetDialogBaseUnits() const + { + return m_sizeUnits; + } + + INT MapDialogPixelsX(INT x) const + { + return ::MulDiv(x, 4, m_sizeUnits.cx); // Pixels X to DLU + } + + INT MapDialogPixelsY(INT y) const + { + return ::MulDiv(y, 8, m_sizeUnits.cy); // Pixels Y to DLU + } + + POINT MapDialogPixels(POINT pt) const + { + POINT out = { MapDialogPixelsX(pt.x), MapDialogPixelsY(pt.y) }; + return out; + } + + SIZE MapDialogPixels(SIZE input) const + { + SIZE out = { MapDialogPixelsX(input.cx), MapDialogPixelsY(input.cy) }; + return out; + } + + RECT MapDialogPixels(RECT input) const + { + RECT out = { MapDialogPixelsX(input.left), MapDialogPixelsY(input.top), MapDialogPixelsX(input.right), MapDialogPixelsY(input.bottom) }; + return out; + } + + INT MapDialogUnitsX(INT x) const + { + return ::MulDiv(x, m_sizeUnits.cx, 4); // DLU to Pixels X + } + + INT MapDialogUnitsY(INT y) const + { + return ::MulDiv(y, m_sizeUnits.cx, 8); // DLU to Pixels Y + } + + POINT MapDialogUnits(POINT pt) const + { + POINT out = { MapDialogUnitsX(pt.x), MapDialogUnitsY(pt.y) }; + return out; + } + + SIZE MapDialogUnits(SIZE input) const + { + SIZE out = { MapDialogUnitsX(input.cx), MapDialogUnitsY(input.cy) }; + return out; + } + + RECT MapDialogUnits(RECT input) const + { + RECT out = { MapDialogUnitsX(input.left), MapDialogUnitsY(input.top), MapDialogUnitsX(input.right), MapDialogUnitsY(input.bottom) }; + return out; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX + +#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; + DWORD id; + }; + #pragma pack(pop) +#endif // (_ATL_VER >= 0x800) + + +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_hData(NULL), 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()) { +#ifndef UNDER_CE + ::GlobalUnlock(m_pData); +#endif + ATLVERIFY(::GlobalFree(m_hData) == NULL); + } + + m_hData = NULL; + m_pData = NULL; + m_pPtr = NULL; + m_cAllocated = 0; + } + + void Create(bool bDlgEx, LPCTSTR lpszCaption, RECT rc, 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) + { + Create(bDlgEx, lpszCaption, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle, + lpstrFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName.m_lpstr, Menu.m_lpstr); + } + + 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, RECT rc, DWORD dwStyle, DWORD dwExStyle, + ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) + { + AddControl(ClassName.m_lpstr, wId, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle, + Text.m_lpstr, pCreationData, nCreationData, dwHelpID); + } + + 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); + } + + 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_hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, m_cAllocated); + ATLASSERT(m_hData != NULL); +#ifndef UNDER_CE + m_pPtr = m_pData = static_cast(::GlobalLock(m_hData)); +#else + m_pPtr = m_pData = static_cast(m_hData); +#endif + 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; +#ifndef UNDER_CE + ::GlobalUnlock(m_pData); +#endif + m_hData = ::GlobalReAlloc(m_hData, m_cAllocated, GMEM_MOVEABLE | GMEM_ZEROINIT); + ATLASSERT(m_hData != NULL); +#ifndef UNDER_CE + m_pData = static_cast(::GlobalLock(m_hData)); +#else + m_pData = static_cast(m_hData); +#endif + 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)); + } + } + + HANDLE m_hData; + 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(), + IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), + IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), + IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), + dwCommonButtons, + IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : 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(), + IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), + IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), + IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), + dwCommonButtons, + IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : 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/atldwm.h b/wtl/wtl/include/atldwm.h new file mode 100644 index 00000000..fea82548 --- /dev/null +++ b/wtl/wtl/include/atldwm.h @@ -0,0 +1,461 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __ATLDWM_H__ +#define __ATLDWM_H__ + +#pragma once + +#ifdef _WIN32_WCE + #error atldwm.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atldwm.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atldwm.h requires atlwin.h to be included first +#endif + +#if (_WIN32_WINNT < 0x0600) + #error atldwm.h requires _WIN32_WINNT >= 0x0600 +#endif // (_WIN32_WINNT < 0x0600) + +#ifndef _DWMAPI_H_ +#include +#endif // _DWMAPI_H_ +#pragma comment(lib, "dwmapi.lib") + +// Note: To create an application that also runs on older versions of Windows, +// use delay load of dwmapi.dll and ensure that no calls to the DWM API are +// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, +// and add dwmapi.dll in the Linker.Input.Delay Loaded DLLs section of the +// project properties. +#if (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) + #pragma comment(lib, "delayimp.lib") + #pragma comment(linker, "/delayload:dwmapi.dll") +#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CDwm +// CDwmImpl +// CDwmWindowT - CDwmWindow +// CDwmThumbnailT +// CDwmThumbnail +// CDwmThumbnailHandle +// CAeroControlImpl + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CDwm - wrapper for DWM handle + +class CDwm +{ +public: +// Data members + static int m_nIsDwmSupported; + +// Constructor + CDwm() + { + IsDwmSupported(); + } + +// Dwm support helper + static bool IsDwmSupported() + { + if(m_nIsDwmSupported == -1) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDwm::IsDwmSupported.\n")); + ATLASSERT(FALSE); + return false; + } + + if(m_nIsDwmSupported == -1) + { + HMODULE hDwmDLL = ::LoadLibrary(_T("dwmapi.dll")); + m_nIsDwmSupported = (hDwmDLL != NULL) ? 1 : 0; + if(hDwmDLL != NULL) + ::FreeLibrary(hDwmDLL); + } + + lock.Unlock(); + } + + ATLASSERT(m_nIsDwmSupported != -1); + return (m_nIsDwmSupported == 1); + } + +// Operations + BOOL DwmIsCompositionEnabled() const + { + if(!IsDwmSupported()) return FALSE; + BOOL bRes = FALSE; + return SUCCEEDED(::DwmIsCompositionEnabled(&bRes)) && bRes; + } + + BOOL DwmEnableComposition(UINT fEnable) + { + if(!IsDwmSupported()) return FALSE; + return SUCCEEDED(::DwmEnableComposition(fEnable)); + } + + BOOL DwmEnableMMCSS(BOOL fEnableMMCSS) + { + if(!IsDwmSupported()) return FALSE; + return SUCCEEDED(::DwmEnableMMCSS(fEnableMMCSS)); + } + + HRESULT DwmGetColorizationColor(DWORD* pcrColorization, BOOL* pfOpaqueBlend) + { + if(!IsDwmSupported()) return E_NOTIMPL; + return ::DwmGetColorizationColor(pcrColorization, pfOpaqueBlend); + } + + HRESULT DwmFlush() + { + if(!IsDwmSupported()) return E_NOTIMPL; + return ::DwmFlush(); + } +}; + +__declspec(selectany) int CDwm::m_nIsDwmSupported = -1; + + +/////////////////////////////////////////////////////////////////////////////// +// CDwmImpl - DWM window support + +template +class CDwmImpl : public TBase +{ +public: + HRESULT DwmEnableBlurBehindWindow(const DWM_BLURBEHIND* pBB) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmEnableBlurBehindWindow(pT->m_hWnd, pBB); + } + + HRESULT DwmExtendFrameIntoClientArea(const MARGINS* pMargins) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmExtendFrameIntoClientArea(pT->m_hWnd, pMargins); + } + + HRESULT DwmExtendFrameIntoEntireClientArea() + { + MARGINS margins = { -1 }; + return DwmExtendFrameIntoClientArea(&margins); + } + + HRESULT DwmGetCompositionTimingInfo(DWM_TIMING_INFO* pTimingInfo) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmGetCompositionTimingInfo(pT->m_hWnd, pTimingInfo); + } + + HRESULT DwmGetWindowAttribute(DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmGetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); + } + + HRESULT DwmModifyPreviousDxFrameDuration(INT cRefreshes, BOOL fRelative) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmModifyPreviousDxFrameDuration(pT->m_hWnd, cRefreshes, fRelative); + } + + HRESULT DwmSetDxFrameDuration(INT cRefreshes) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmSetDxFrameDuration(pT->m_hWnd, cRefreshes); + } + + HRESULT DwmSetPresentParameters(DWM_PRESENT_PARAMETERS* pPresentParams) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmSetPresentParameters(pT->m_hWnd, pPresentParams); + } + + HRESULT DwmSetWindowAttribute(DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmSetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); + } + + HRESULT DwmAttachMilContent() + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmAttachMilContent(pT->m_hWnd); + } + + HRESULT DwmDetachMilContent() + { + if(!IsDwmSupported()) return E_NOTIMPL; + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmDetachMilContent(pT->m_hWnd); + } +}; + +template +class CDwmWindowT : public TBase, public CDwmImpl > +{ +public: + CDwmWindowT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CDwmWindowT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } +}; + +typedef CDwmWindowT CDwmWindow; + + +/////////////////////////////////////////////////////////////////////////////// +// CDwmThumbnail - provides DWM thumbnail support + +template +class CDwmThumbnailT : public TBase +{ +public: +// Data members + HTHUMBNAIL m_hThumbnail; + +// Constructor + CDwmThumbnailT(HTHUMBNAIL hThumbnail = NULL) : m_hThumbnail(hThumbnail) + { + } + + ~CDwmThumbnailT() + { + if(t_bManaged && m_hThumbnail != NULL) + Unregister(); + } + +// Operations + CDwmThumbnailT& operator =(HTHUMBNAIL hThumbnail) + { + Attach(hThumbnail); + return *this; + } + + void Attach(HTHUMBNAIL hThumbnailNew) + { + if(t_bManaged && m_hThumbnail != NULL && m_hThumbnail != hThumbnailNew) + Unregister(); + m_hThumbnail = hThumbnailNew; + } + + HTHUMBNAIL Detach() + { + HTHUMBNAIL hThumbnail = m_hThumbnail; + m_hThumbnail = NULL; + return hThumbnail; + } + + HRESULT Register(HWND hwndDestination, HWND hwndSource) + { + ATLASSERT(::IsWindow(hwndDestination)); + ATLASSERT(::IsWindow(hwndSource)); + ATLASSERT(m_hThumbnail==NULL); + if(!IsDwmSupported()) return E_NOTIMPL; + return ::DwmRegisterThumbnail(hwndDestination, hwndSource, &m_hThumbnail); + } + + HRESULT Unregister() + { + if(!IsDwmSupported()) return E_NOTIMPL; + if(m_hThumbnail == NULL) return S_FALSE; + HRESULT Hr = ::DwmUnregisterThumbnail(m_hThumbnail); + if(SUCCEEDED(Hr)) m_hThumbnail = NULL; + return Hr; + } + + operator HTHUMBNAIL() const { return m_hThumbnail; } + + bool IsNull() const { return (m_hThumbnail == NULL); } + + HRESULT UpdateProperties(const DWM_THUMBNAIL_PROPERTIES* ptnProperties) + { + if(!IsDwmSupported()) return E_NOTIMPL; + ATLASSERT(m_hThumbnail != NULL); + return ::DwmUpdateThumbnailProperties(m_hThumbnail, ptnProperties); + } + +// Attributes + HRESULT QuerySourceSize(PSIZE pSize) + { + if(!IsDwmSupported()) return E_NOTIMPL; + ATLASSERT(m_hThumbnail != NULL); + return ::DwmQueryThumbnailSourceSize(m_hThumbnail, pSize); + } +}; + +typedef CDwmThumbnailT CDwmThumbnail; +typedef CDwmThumbnailT CDwmThumbnailHandle; + + +#ifdef __ATLTHEME_H__ + +/////////////////////////////////////////////////////////////////////////////// +// CAeroControlImpl - Base class for controls on Glass + +template +class CAeroControlImpl : + public CThemeImpl, + public CBufferedPaintImpl, + public ATL::CWindowImpl +{ +public: + typedef CThemeImpl _themeClass; + typedef CBufferedPaintImpl _baseClass; + typedef ATL::CWindowImpl _windowClass; + + CAeroControlImpl() + { + m_PaintParams.dwFlags = BPPF_ERASE; + } + + static LPCWSTR GetThemeName() + { +#ifdef _UNICODE + return TBase::GetWndClassName(); +#else + ATLASSERT(!_T("Return UNICODE string of window classname / theme class")); + return NULL; +#endif // _UNICODE + } + +// Message map and handlers + BEGIN_MSG_MAP(CAeroControlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + CHAIN_MSG_MAP(_themeClass) + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->Init(); + bHandled = FALSE; + return 0; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(IsThemingSupported()) Invalidate(FALSE); + bHandled = FALSE; + return 0; + } + +// Operations + BOOL SubclassWindow(HWND hWnd) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + BOOL bRet = _windowClass::SubclassWindow(hWnd); + if(bRet) { + T* pT = static_cast(this); + pT->Init(); + } + return bRet; + } + +// Implementation + LRESULT DefWindowProc() + { + const _ATL_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) + { + T* pT = static_cast(this); + LRESULT lRes = 0; + if( ::DwmDefWindowProc(pT->m_hWnd, uMsg, wParam, lParam, &lRes) ) return lRes; + return _windowClass::DefWindowProc(uMsg, wParam, lParam); + } + + void DoBufferedPaint(HDC hDC, RECT& rcPaint) + { + T* pT = static_cast(this); + HDC hDCPaint = NULL; + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + m_BufferedPaint.Begin(hDC, &rcClient, m_dwFormat, &m_PaintParams, &hDCPaint); + ATLASSERT(hDCPaint != NULL); + pT->DoAeroPaint(hDCPaint, rcClient, rcPaint); + m_BufferedPaint.End(); + } + + void DoPaint(HDC /*hdc*/, RECT& /*rcClient*/) + { + DefWindowProc(); + } + +// Overridables + void Init() + { + T* pT = static_cast(this); + SetThemeClassList(pT->GetThemeName()); + if(m_lpstrThemeClassList != NULL) + OpenThemeData(); + } + + void DoAeroPaint(HDC hDC, RECT& /*rcClient*/, RECT& rcPaint) + { + DefWindowProc(WM_PAINT, (WPARAM) hDC, 0L); + m_BufferedPaint.MakeOpaque(&rcPaint); + } +}; + +#endif // __ATLTHEME_H__ + + +}; // namespace WTL + + +#endif // __ATLDWM_H__ diff --git a/wtl/wtl/include/atlfind.h b/wtl/wtl/include/atlfind.h new file mode 100644 index 00000000..832aba20 --- /dev/null +++ b/wtl/wtl/include/atlfind.h @@ -0,0 +1,1032 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 + +#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 != FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// 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..92b2170f --- /dev/null +++ b/wtl/wtl/include/atlframe.h @@ -0,0 +1,3699 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 +// CAutoUpdateUI +// 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) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + struct _ChevronMenuInfo + { + HMENU hMenu; + LPNMREBARCHEVRON lpnm; + bool bCmdBar; + }; +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Data members + HWND m_hWndToolBar; + HWND m_hWndStatusBar; + HWND m_hWndClient; + +#ifdef _WIN32_WCE + HWND m_hWndCECommandBar; +#endif // _WIN32_WCE + + HACCEL m_hAccel; + +// Constructor + CFrameWindowImplBase() : + m_hWndToolBar(NULL), + m_hWndStatusBar(NULL), + m_hWndClient(NULL), +#ifdef _WIN32_WCE + m_hWndCECommandBar(NULL), +#endif // _WIN32_WCE + 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 = (HFONT)::GetStockObject(SYSTEM_FONT); + 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 != FALSE) + { + ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); + ::InvalidateRect(m_hWndToolBar, NULL, TRUE); + } + 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 != FALSE) + ::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; + struct + { + WORD m_nIDFirst; + WORD m_nIDLast; + }; + }; + + 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); + + if((pUIData->m_wState & UPDUI_RADIO) != 0) + ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND); + } + 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; + } + + // for menu items + BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, 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) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_RADIO; + pUIData->m_nIDFirst = (WORD)nIDFirst; + pUIData->m_nIDLast = (WORD)nIDLast; + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + } + else if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast) + { + if(pUIData->m_wState & UPDUI_RADIO) + { + pUIData->m_wState &= ~pMap->m_wType; + pUIData->m_wState &= ~UPDUI_RADIO; + pUIData->m_nIDFirst = 0; + pUIData->m_nIDLast = 0; + } + } + + if(pMap->m_nID == nIDLast) + break; + } + + 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; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAutoUpdateUI : Automatic mapping of UI elements + +template +class CAutoUpdateUI : public CDynamicUpdateUI +{ +public: + LPCTSTR UIGetText(int nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + return m_arrUIData[i].m_lpstrText; + } + + return NULL; + } + +// Element + template + bool UIAddElement(UINT nID) + { + // check for existing UI map element + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + { + // set requested type + m_arrUIMap[i].m_wType |= t_wType; + return true; + } + } + + // Add element to UI map with requested type + return UIAddUpdateElement((WORD)nID, t_wType); + } + + template + bool UIRemoveElement(UINT nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) // matching UI map element + { + WORD wType = m_arrUIMap[i].m_wType & ~t_wType; + if (wType) // has other types + { + m_arrUIMap[i].m_wType = wType; // keep other types + return true; + } + else + { + return UIRemoveUpdateElement((WORD)nID); + } + } + } + + return false; + } + +// Menu + bool UIAddMenu(HMENU hMenu, bool bSetText = false) + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + using ATL::GetMenuString; +#endif + ATLASSERT(::IsMenu(hMenu)); + MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU}; + + // Complete the UI map + for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++) + { + if(mii.hSubMenu) + { + // Add submenu to UI map + UIAddMenu(mii.hSubMenu, bSetText); + } + else if (mii.wID) + { + // Add element to UI map + UIAddElement(mii.wID); +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + if (bSetText) + { + TCHAR sText[64] = { 0 }; + if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION)) + UISetText(mii.wID, sText); + } +#else + bSetText; +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + } + } + + return true; + } + + bool UIAddMenu(UINT uID, bool bSetText = false) + { + CMenu menu; + ATLVERIFY(menu.LoadMenu(uID)); + return UIAddMenu(menu, bSetText); + } + +// ToolBar +#ifndef BTNS_SEP + #define BTNS_SEP TBSTYLE_SEP +#endif // BTNS_SEP compatibility + +#if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) + bool UIAddToolBar(HWND hWndToolBar) + { + ATLASSERT(::IsWindow(hWndToolBar)); + TBBUTTONINFO tbbi = {sizeof TBBUTTONINFO, TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX}; + + // Add toolbar buttons + for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++) + { + if (tbbi.fsStyle ^ BTNS_SEP) + UIAddElement(tbbi.idCommand); + } + + // Add embedded controls if any + if (::GetWindow(hWndToolBar, GW_CHILD)) + UIAddChildWindowContainer(hWndToolBar); + + return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE); + } +#endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) + +// Container + bool UIAddChildWindowContainer(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + + // Add children controls if any + for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT)) + { + if (int id = wCtl.GetDlgCtrlID()) + UIAddElement(id); + } + + return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE); + } + +// StatusBar + BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) + return TRUE; + + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + for(int e = 0; e < m_UIElements.GetSize(); e++) + { + if((m_UIElements[e].m_wType == UPDUI_STATUSBAR) && + (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) && + (m_arrUIData[i].m_wState & UPDUI_STATUSBAR)) + { + UIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd); + m_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR; + if(m_arrUIData[i].m_wState & UPDUI_TEXT) + m_arrUIData[i].m_wState &= ~UPDUI_TEXT; + } + } + } + + m_wDirtyType &= ~UPDUI_STATUSBAR; + return TRUE; + } + + bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1) + { + ATLASSERT(::IsWindow(hWndStatusBar)); + + // Add StatusBar panes + for (int iPane = 0; iPane < nPanes; iPane++) + UIAddElement(ID_DEFAULT_PANE + iPane); + + return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE); + } + +// UI Map used if derived class has none + BEGIN_UPDATE_UI_MAP(CAutoUpdateUI) + END_UPDATE_UI_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// 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..1e452c4d --- /dev/null +++ b/wtl/wtl/include/atlgdi.h @@ -0,0 +1,3891 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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) + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); + // For MM_TEXT mapping mode + lfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(hDC1, LOGPIXELSY), 72); + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + } + + LONG GetHeight(HDC hDC = NULL) const + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); + // For MM_TEXT mapping mode + LONG nPointSize = ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC1, LOGPIXELSY)); + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + + return nPointSize; + } + + LONG GetDeciPointHeight(HDC hDC = NULL) const + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); +#ifndef _WIN32_WCE + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC1, &ptOrg, 1); + POINT pt = { 0, 0 }; + pt.y = abs(lfHeight) + ptOrg.y; + ::LPtoDP(hDC1, &pt,1); + LONG nDeciPoint = ::MulDiv(pt.y, 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point +#else // CE specific + // DP and LP are always the same on CE + LONG nDeciPoint = ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + + return nDeciPoint; + } + + void SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC hDC = NULL) + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); +#ifndef _WIN32_WCE + POINT pt = { 0, 0 }; + pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720); // 72 points/inch, 10 decipoints/point + ::DPtoLP(hDC1, &pt, 1); + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC1, &ptOrg, 1); + lfHeight = -abs(pt.y - ptOrg.y); +#else // CE specific + // DP and LP are always the same on CE + lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + } + +#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); + } + + BOOL GradientFillRect(RECT& rect, COLORREF clr1, COLORREF clr2, bool bHorizontal) + { + ATLASSERT(m_hDC != NULL); + + TRIVERTEX arrTvx[2] = { { 0 }, { 0 } }; + + arrTvx[0].x = rect.left; + arrTvx[0].y = rect.top; + arrTvx[0].Red = MAKEWORD(0, GetRValue(clr1)); + arrTvx[0].Green = MAKEWORD(0, GetGValue(clr1)); + arrTvx[0].Blue = MAKEWORD(0, GetBValue(clr1)); + arrTvx[0].Alpha = 0; + + arrTvx[1].x = rect.right; + arrTvx[1].y = rect.bottom; + arrTvx[1].Red = MAKEWORD(0, GetRValue(clr2)); + arrTvx[1].Green = MAKEWORD(0, GetGValue(clr2)); + arrTvx[1].Blue = MAKEWORD(0, GetBValue(clr2)); + arrTvx[1].Alpha = 0; + + GRADIENT_RECT gr = { 0, 1 }; + + return ::GradientFill(m_hDC, arrTvx, 2, &gr, 1, bHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V); + } +#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; + SecureHelper::memcpy_x(bmiColors, sizeof(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) +{ + CDC dc(NULL); + void* pBits = NULL; + + LPBYTE pDibBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER) + AtlGetDibColorTableSize(&pbmi->bmiHeader) * sizeof(RGBQUAD); + HBITMAP hbm = CreateDIBSection(dc, pbmi, DIB_RGB_COLORS, &pBits, NULL, NULL); + if (hbm != NULL) + { + int cbBits = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biHeight * pbmi->bmiHeader.biBitCount / 8; + SecureHelper::memcpy_x(pBits, cbBits, 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 != FALSE) && (AtlIsDib16(&ds.dsBmih) != FALSE) && (ds.dsBm.bmBits != NULL)) + { + pDib = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage); + if (pDib != NULL) + { + SecureHelper::memcpy_x(pDib, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage, &ds.dsBmih, sizeof(DIBINFO16)); + SecureHelper::memcpy_x(pDib + sizeof(DIBINFO16), ds.dsBmih.biSizeImage, 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 != FALSE) + { + bOK = EmptyClipboard(); + if (bOK != FALSE) + { + 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 != FALSE); +} + +inline HBITMAP AtlGetClipboardDib(HWND hWnd) +{ + ATLASSERT(::IsWindow(hWnd) != FALSE); + HBITMAP hbm = NULL; + if (OpenClipboard(hWnd) != FALSE) + { + 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..dd760ca0 --- /dev/null +++ b/wtl/wtl/include/atlmisc.h @@ -0,0 +1,3746 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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: +// 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 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 _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 + } +#else // !_ATL_MIN_CRT + static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) + { + return _tcschr(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 _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 +#endif // !_ATL_MIN_CRT + + static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch) + { + return MinCrtHelper::_strrchr(p, ch); + } + + static int _cstrisdigit(TCHAR ch) + { + return MinCrtHelper::_isdigit(ch); + } + + static int _cstrisspace(TCHAR ch) + { + return MinCrtHelper::_isspace(ch); + } + + static int _cstrtoi(const TCHAR* nptr) + { + return MinCrtHelper::_atoi(nptr); + } + + 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); + CRegKeyEx rkParent; + CRegKeyEx 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; + lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet); + 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); + ULONG ulCount = t_cchItemLen; + lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount); + 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 + CRegKeyEx rkParent; + CRegKeyEx 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; + + lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries); + 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); + lRet = rk.SetStringValue(szBuff, szDocName); + 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 = MinCrtHelper::_strrchr(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 = MinCrtHelper::_strrchr(m_lpszRoot, _T('\\')); + LPTSTR pstrFront = MinCrtHelper::_strrchr(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; + } + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// 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..50a7fb17 --- /dev/null +++ b/wtl/wtl/include/atlprint.h @@ -0,0 +1,1109 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 + +#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..22fb3e6f --- /dev/null +++ b/wtl/wtl/include/atlres.h @@ -0,0 +1,263 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 +#define ID_VIEW_RIBBON 0xE804 // Ribbon + +/////////////////////////////////////////////////////////////////////////////// +// 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..3b2b9338 --- /dev/null +++ b/wtl/wtl/include/atlresce.h @@ -0,0 +1,93 @@ +// Windows Template Library - WTL version 8.1 +// 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/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/atlribbon.h b/wtl/wtl/include/atlribbon.h new file mode 100644 index 00000000..2f59cfa1 --- /dev/null +++ b/wtl/wtl/include/atlribbon.h @@ -0,0 +1,3446 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __ATLRIBBON_H__ +#define __ATLRIBBON_H__ + +#pragma once + +#if (_MSC_VER < 1500) + #error atlribbon.h requires Visual C++ 2008 compiler or higher +#endif + +#ifndef _UNICODE + #error atlribbon.h requires the Unicode character set +#endif + +#if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7) + #error atlribbon.h requires the Windows 7 SDK or higher +#endif + +#ifdef _WIN32_WCE + #error atlribbon.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atlribbon.h requires atlapp.h to be included first +#endif + +#if (_ATL_VER < 0x0700) + #include + #pragma comment(lib, "shlwapi.lib") +#endif + +#include // for RecentDocumentList classes +#include // for Frame and UpdateUI classes +#include // required for atlctrlw.h +#include // for CCommandBarCtrl + +#if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__) + #pragma warning(disable : 4530) // unwind semantics not enabled + #include + #pragma warning(default : 4530) +#endif + +#include +#pragma comment(lib, "dwmapi.lib") + +#include +#include +#pragma comment(lib, "propsys.lib") + +#include // for CHARFORMAT2 + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CRibbonUpdateUI : Automatic mapping of ribbon UI elements +// +// RibbonUI::Text +// RibbonUI::CharFormat +// RibbonUI::ICtrl +// RibbonUI::CtrlImpl +// RibbonUI::CommandCtrlImpl +// RibbonUI::ItemProperty +// RibbonUI::CollectionImplBase +// RibbonUI::CollectionImpl +// RibbonUI::TextCollectionImpl +// RibbonUI::ItemCollectionImpl +// RibbonUI::ComboCollectionImpl +// RibbonUI::CommandCollectionImpl +// RibbonUI::ToolbarCollectionImpl +// RibbonUI::SimpleCollectionImpl +// RibbonUI::CollectionCtrlImpl +// RibbonUI::ToolbarGalleryCtrlImpl +// RibbonUI::SimpleCollectionCtrlImpl +// RibbonUI::RecentItemsCtrlImpl +// RibbonUI::FontCtrlImpl +// RibbonUI::ColorCtrlImpl +// RibbonUI::SpinnerCtrlImpl +// +// RibbonUI::CRibbonImpl +// CRibbonImpl::CRibbonComboCtrl +// CRibbonImpl::CRibbonItemGalleryCtrl +// CRibbonImpl::CRibbonCommandGalleryCtrl +// CRibbonImpl::CRibbonToolbarGalleryCtrl +// CRibbonImpl::CRibbonSimpleComboCtrl +// CRibbonImpl::CRibbonSimpleGalleryCtrl +// CRibbonImpl::CRibbonRecentItemsCtrl +// CRibbonImpl::CRibbonColorCtrl +// CRibbonImpl::CRibbonFontCtrl +// CRibbonImpl::CRibbonSpinnerCtrl +// CRibbonImpl::CRibbonFloatSpinnerCtrl +// CRibbonImpl::CRibbonCommandCtrl +// +// CRibbonFrameWindowImplBase +// CRibbonFrameWindowImpl +// CRibbonMDIFrameWindowImpl +// CRibbonPersist +// +// Global functions: +// RibbonUI::SetPropertyVal() +// RibbonUI::GetImage() + + +// Constants + +#ifndef RIBBONUI_MAX_TEXT + #define RIBBONUI_MAX_TEXT 128 +#endif + +#define TWIPS_PER_POINT 20 // For font size + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CRibbonUpdateUI : Automatic mapping of ribbon UI elements + +template +class CRibbonUpdateUI : public CAutoUpdateUI +{ +public: + enum + { + UPDUI_RIBBON = 0x0080, + UPDUI_PERSIST = 0x0020 + }; + + bool IsRibbonElement(const _AtlUpdateUIMap& UIMap) + { + return (UIMap.m_wType & UPDUI_RIBBON) != 0; + } + + bool IsRibbonID(UINT nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + return IsRibbonElement(m_arrUIMap[i]); + } + + return false; + } + +// Element + bool UIAddRibbonElement(UINT nID) + { + return UIAddElement(nID); + } + + bool UIRemoveRibbonElement(UINT nID) + { + return UIRemoveElement(nID); + } + + bool UIPersistElement(UINT nID, bool bPersist = true) + { + return bPersist ? + UIAddElement(nID) : + UIRemoveElement(nID); + } + +// methods for Ribbon elements + BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE) + { + T* pT = static_cast(this); + BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate); + if (pT->IsRibbonUI() && IsRibbonID(nID)) + bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label)); + return bRes; + } + + BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE) + { + CTempBuffer sText(RIBBONUI_MAX_TEXT); + return AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT) ? + UISetText(nID, sText, bForceUpdate) : + E_FAIL; + } + + LPCTSTR UIGetText(int nID) + { + T* pT = static_cast(this); + LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID); + + // replace 'tab' by 'space' for RibbonUI elements + if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t')) + { + static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; + wcscpy_s(sText, sUI); + *wcschr(sText, L'\t') = L' '; + return sText; + } + else + { + return sUI; + } + } + + BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) + { + T* pT = static_cast(this); + BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate); + if (pT->IsRibbonUI() && IsRibbonID(nID)) + bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable)); + return bRes; + } + + BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE) + { + if ((nCheck == 0) || (nCheck == 1)) + return UISetCheck(nID, nCheck != 0, bForceUpdate); + else + return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate); + } + + BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) + { + T* pT = static_cast(this); + BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate); + if (bRes && pT->IsRibbonUI() && IsRibbonID(nID)) + bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck)); + return bRes; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// RibbonUI namespace +// + +namespace RibbonUI +{ + +// Minimal string allocation support for various PROPERTYKEY values +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + typedef _CSTRING_NS::CString Text; +#else + class Text : public std::wstring + { + public: + Text(std::wstring& s) : std::wstring(s) + { } + Text(LPCWSTR s) : std::wstring(s) + { } + Text() + { } + bool IsEmpty() + { + return empty(); + } + operator LPCWSTR() + { + return c_str(); + } + Text& operator =(LPCWSTR s) + { + return static_cast(std::wstring::operator =(s)); + } + }; +#endif + +// PROPERTYKEY enum and helpers +enum k_KEY +{ + // state + k_Enabled = 1, k_BooleanValue = 200, + // text properties + k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6, + // image properties + k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10, + // collection properties + k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104, + // collection item properties + k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106, + // combo control property + k_StringValue = 202, + // spinner control properties + k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208, + // font control properties + k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304, + k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308, + k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312, + k_FontProperties_DeltaSize = 313, + // recent items properties + k_RecentItems = 350, k_Pinned = 351, + // color control properties + k_Color = 400, k_ColorType = 401, k_ColorMode, + k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406, + k_NoColorLabel = 407, k_MoreColorsLabel = 408, + k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412, + // Ribbon state + k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100, + // Ribbon UI colors + k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002 +}; + +inline k_KEY k_(REFPROPERTYKEY key) +{ + return (k_KEY)key.fmtid.Data1; +} + +// PROPERTYKEY value assignment and specializations +// +template +HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv) +{ + switch (k_(key)) + { + case k_Enabled: + case k_BooleanValue: + return InitPropVariantFromBoolean(val, ppv); + default: + return UIInitPropertyFromUInt32(key, val, ppv); + } +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv) +{ + return SetPropertyVal(key, (LONG)val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv) +{ + HRESULT hr = UIInitPropertyFromImage(key, val, ppv); + ATLVERIFY(val->Release() == 1); + return hr; +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromInterface(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromInterface(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromIUnknownArray(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromDecimal(key, *val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromBoolean(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromString(key, val, ppv); +} + +// CharFormat helper struct for RibbonUI font control +// +struct CharFormat : CHARFORMAT2 +{ + // Default constructor + CharFormat() + { + cbSize = sizeof CHARFORMAT2; + Reset(); + } + + // Copy constructor + CharFormat(const CharFormat& cf) + { + CopyMemory(this, &cf, sizeof CHARFORMAT2); + } + + // Assign operator + CharFormat& operator =(const CharFormat& cf) + { + CopyMemory(this, &cf, sizeof CHARFORMAT2); + return (*this); + } + + void Reset() + { + uValue = dwMask = dwEffects = 0; + PropVariantInit(&propvar); + } + + void operator <<(IPropertyStore* pStore) + { + if (pStore == NULL) + { + ATLASSERT(FALSE); + return; + } + + static void (CharFormat::*Getk_[])(IPropertyStore*) = + { + &CharFormat::Getk_Family, + &CharFormat::Getk_FontProperties_Size, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_VerticalPositioning, + &CharFormat::Getk_Color, + &CharFormat::Getk_Color, + &CharFormat::Getk_ColorType, + &CharFormat::Getk_ColorType, + }; + + DWORD nProps = 0; + Reset(); + + ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps))); + for (DWORD iProp = 0; iProp < nProps; iProp++) + { + PROPERTYKEY key; + ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key))); + ATLASSERT(k_(key) >= k_FontProperties_Family); + + if (k_(key) <= k_FontProperties_BackgroundColorType) + (this->*Getk_[k_(key) - k_FontProperties_Family])(pStore); + } + } + + void operator >>(IPropertyStore* pStore) + { + if (pStore == NULL) + { + ATLASSERT(FALSE); + return; + } + + PutFace(pStore); + PutSize(pStore); + PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore); + PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore); + PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore); + PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore); + PutVerticalPos(pStore); + PutColor(pStore); + PutBackColor(pStore); + } + +private: + PROPVARIANT propvar; + UINT uValue; + + // Getk_ functions + void Getk_Family(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar))) + { + PropVariantToString(propvar, szFaceName, LF_FACESIZE); + if (*szFaceName) + dwMask |= CFM_FACE; + } + } + + void Getk_FontProperties_Size(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar))) + { + DECIMAL decSize; + UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize); + DOUBLE dSize; + VarR8FromDec(&decSize, &dSize); + if (dSize > 0) + { + dwMask |= CFM_SIZE; + yHeight = (LONG)(dSize * TWIPS_PER_POINT); + } + } + } + + template + void Getk_MaskEffect(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(key, &propvar))) + { + UIPropertyToUInt32(key, propvar, &uValue); + if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE) + { + dwMask |= t_dwMask; + dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0; + } + } + } + + void Getk_VerticalPositioning(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar))) + { + UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue); + UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue; + if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE)) + { + dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT); + if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET) + { + dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT; + } + } + } + } + + template + void Getk_Color(IPropertyStore* pStore) + { + UINT32 color; + if (SUCCEEDED(pStore->GetValue(key, &propvar))) + { + UIPropertyToUInt32(key, propvar, &color); + dwMask |= t_dwMask; + + if (t_dwMask == CFM_COLOR) + crTextColor = color; + else + crBackColor = color; + } + } + + template + void Getk_ColorType(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(key, &propvar))) + { + UIPropertyToUInt32(key, propvar, &uValue); + if (t_type == (UI_SWATCHCOLORTYPE)uValue) + { + dwMask |= t_dwMask; + dwEffects |= t_dwEffects; + } + } + } + + // Put functions + void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore) + { + PROPVARIANT propvar; + UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE; + if ((dwMask & dwMaskVal) != 0) + uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET; + SetPropertyVal(key, uProp, &propvar); + pStore->SetValue(key, propvar); + } + + void PutVerticalPos(IPropertyStore* pStore) + { + PROPVARIANT propvar; + UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE; + + if ((dwMask & CFE_SUBSCRIPT) != 0) + { + if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT)) + uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; + else + uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; + } + else if ((dwMask & CFM_OFFSET) != 0) + { + if (yOffset > 0) + uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; + else if (yOffset < 0) + uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; + } + + SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, propvar); + } + + void PutFace(IPropertyStore* pStore) + { + PROPVARIANT propvar; + SetPropertyVal(UI_PKEY_FontProperties_Family, + dwMask & CFM_FACE ? szFaceName : L"", &propvar); + pStore->SetValue(UI_PKEY_FontProperties_Family, propvar); + } + + void PutSize(IPropertyStore* pStore) + { + PROPVARIANT propvar; + DECIMAL decVal; + + if ((dwMask & CFM_SIZE) != 0) + VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal); + else + VarDecFromI4(0, &decVal); + + SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_Size, propvar); + } + + void PutColor(IPropertyStore* pStore) + { + if ((dwMask & CFM_COLOR) != 0) + if ((dwEffects & CFE_AUTOCOLOR) == 0) + { + SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); + + SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar); + } + else + { + SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); + } + } + + void PutBackColor(IPropertyStore* pStore) + { + if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0)) + { + SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); + + SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar); + } + else + { + SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); + } + } +}; + +// IUIImage helper +// +inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner) +{ + ATLASSERT(hbm); + IUIImage* pIUII = NULL; + ATL::CComPtr pIFB; + + if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory)) + ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII))); + + return pIUII; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon control classes + +// RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes +// +struct ICtrl +{ + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) = 0; + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0; +}; + +// RibbonUI::CtrlImpl base class for all ribbon controls +// +template +class ATL_NO_VTABLE CtrlImpl : public ICtrl +{ +protected: + T* m_pWndRibbon; + +public: + typedef T WndRibbon; + + CtrlImpl() : m_pWndRibbon(T::pWndRibbon) + { } + + WndRibbon& GetWndRibbon() + { + return *m_pWndRibbon; + } + + static WORD GetID() + { + return t_ID; + } + + Text m_sTxt[5]; + + // Operations + HRESULT Invalidate() + { + return GetWndRibbon().InvalidateCtrl(GetID()); + } + + HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) + { + return GetWndRibbon().InvalidateProperty(GetID(), key, flags); + } + + HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false) + { + ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); + + m_sTxt[k_(key) - k_LabelDescription] = sTxt; + + return bUpdate ? + GetWndRibbon().InvalidateProperty(GetID(), key) : + S_OK; + } + + // Implementation + template + HRESULT SetProperty(REFPROPERTYKEY key, V val) + { + return GetWndRibbon().SetProperty(GetID(), key, val); + } + + HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv) + { + ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); + + const INT iText = k_(key) - k_LabelDescription; + if (m_sTxt[iText].IsEmpty()) + if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key)) + m_sTxt[iText] = sText; + + return !m_sTxt[iText].IsEmpty() ? + SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) : + S_OK; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + ATLASSERT(nCmdID == t_ID); + return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == t_ID); + + const INT iMax = k_TooltipTitle - k_LabelDescription; + const INT iVal = k_(key) - k_LabelDescription; + + return (iVal <= iMax) && (iVal >= 0) ? + OnGetText(key, ppropvarNewValue) : + GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } +}; + +// CommandCtrlImpl base class for most ribbon controls +// +template +class CommandCtrlImpl : public CtrlImpl +{ +public: + CBitmap m_hbm[4]; + + HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false) + { + ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); + + m_hbm[k_(key) - k_LargeImage].Attach(hbm); + + return bUpdate ? + GetWndRibbon().InvalidateProperty(GetID(), key) : + S_OK; + } + + HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv) + { + ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); + + const INT iImage = k_(key) - k_LargeImage; + + if (m_hbm[iImage].IsNull()) + m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key); + + return m_hbm[iImage].IsNull() ? + E_NOTIMPL : + SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv); + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT (nCmdID == GetID()); + + return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ? + OnGetImage(key, ppropvarNewValue) : + CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon collection base classes + +// ItemProperty class: ribbon callback for each item in a collection +// +template +class ItemProperty : public IUISimplePropertySet +{ +public: + ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection) + { } + + const UINT m_Index; + TCollection* m_pCollection; + + // IUISimplePropertySet method. + STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value) + { + return m_pCollection->OnGetItem(m_Index, key, value); + } + + // IUnknown methods. + STDMETHODIMP_(ULONG) AddRef() + { + return 1; + } + + STDMETHODIMP_(ULONG) Release() + { + return 1; + } + + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet))) + { + *ppv = this; + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } +}; + + +// CollectionImplBase: base class for all RibbonUI collections +// +template +class CollectionImplBase +{ + typedef CollectionImplBase thisClass; + +public: + CollectionImplBase() + { + for (int i = 0; i < t_size; i++) + m_apItems[i] = new ItemProperty(i, static_cast(this)); + } + + ~CollectionImplBase() + { + for (int i = 0; i < t_size; i++) + delete m_apItems[i]; + } + +// Data members + ItemProperty* m_apItems[t_size]; +}; + +// CollectionImpl: handles categories and collecton resizing +// +template +class CollectionImpl : public CollectionImplBase, t_items + t_categories> +{ + typedef CollectionImpl thisClass; +public: + typedef thisClass Collection; + + CollectionImpl() : m_size(t_items) + { + FillMemory(m_auItemCat, sizeof m_auItemCat, 0xff); // UI_COLLECTION_INVALIDINDEX + } + + UINT32 m_auItemCat[t_items]; + Text m_asCatName[max(t_categories, 1)]; + size_t m_size; + +// Operations + HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false) + { + ATLASSERT((uItem < t_items) && (uCat < t_categories)); + + m_auItemCat[uItem] = uCat; + + return bUpdate ? InvalidateItems() : S_OK; + } + + HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false) + { + ATLASSERT(uCat < t_categories); + + m_asCatName[uCat] = sText; + + return bUpdate ? InvalidateCategories() : S_OK; + } + + HRESULT Resize(size_t size, bool bUpdate = false) + { + ATLASSERT(size <= t_items); + + m_size = size; + + return bUpdate ? InvalidateItems() : S_OK; + } + +// Implementation + HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uIndex < t_items + t_categories); + TCtrl* pCtrl = static_cast(this); + + return uIndex < t_items ? + pCtrl->DoGetItem(uIndex, key, value) : + pCtrl->DoGetCategory(uIndex - t_items, key, value); + } + + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(k_(key) == k_CategoryId); + UINT32 uCat = UI_COLLECTION_INVALIDINDEX; + + if (t_categories != 0) + { + if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem); + } + uCat = m_auItemCat[uItem]; + } + + return SetPropertyVal(key, uCat, value); + } + + HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value) + { + HRESULT hr = S_OK; + + switch (k_(key)) + { + case k_Label: + if (m_asCatName[uCat].IsEmpty()) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat); + } + hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value); + break; + case k_CategoryId: + hr = SetPropertyVal(key, uCat, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } + + HRESULT InvalidateItems() + { + return static_cast(this)->Invalidate(UI_PKEY_ItemsSource); + } + + HRESULT InvalidateCategories() + { + return static_cast(this)->Invalidate(UI_PKEY_Categories); + } + + HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/) + { + ATLASSERT(nCmdID == TCtrl::GetID()); + nCmdID; // avoid level 4 warning + + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_ItemsSource: + { + ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); + ATLASSERT(pIUICollection); + hr = pIUICollection->Clear(); + for (UINT i = 0; i < m_size; i++) + { + if FAILED(hr = pIUICollection->Add(m_apItems[i])) + break; + } + ATLASSERT(SUCCEEDED(hr)); + } + break; + case k_Categories: + if (t_categories != 0) + { + ATL::CComQIPtr pIUICategory(ppropvarCurrentValue->punkVal); + ATLASSERT(pIUICategory.p); + hr = pIUICategory->Clear(); + for (UINT i = t_items; i < t_items + t_categories; i++) + { + if FAILED(hr = pIUICategory->Add(m_apItems[i])) + break; + } + ATLASSERT(SUCCEEDED(hr)); + } + break; + } + + return hr; + } +}; + +// TextCollectionImpl: handles item labels and selection +// +template +class TextCollectionImpl : public CollectionImpl +{ + typedef TextCollectionImpl thisClass; +public: + typedef thisClass TextCollection; + + TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX) + { } + + Text m_asText[t_items]; + UINT m_uSelected; + + // Operations + HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false) + { + ATLASSERT(uItem < t_items); + + m_asText[uItem] = sText; + + return bUpdate ? InvalidateItems() : S_OK; + } + + UINT GetSelected() + { + return m_uSelected; + } + + HRESULT Select(UINT uItem, bool bUpdate = false) + { + ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX)); + + m_uSelected = uItem; + + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + return bUpdate ? + ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) : + S_OK; + } + +// Implementation + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_items); + + if (k_(key) == k_Label) + { + if (m_asText[uItem].IsEmpty()) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem); + } + return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value); + } + else + { + return Collection::DoGetItem(uItem, key, value); + } + } + + HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == TCtrl::GetID()); + + if (k_(key) == k_SelectedItem) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + UINT uSel = UI_COLLECTION_INVALIDINDEX; + if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) && + ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel)) + m_uSelected = uSel; + + return SetPropertyVal(key, m_uSelected, ppropvarNewValue); + } + else + { + return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } + } +}; + +// ItemCollectionImpl: handles item image +// +template +class ItemCollectionImpl : public TextCollectionImpl +{ + typedef ItemCollectionImpl thisClass; +public: + typedef thisClass ItemCollection; + + ItemCollectionImpl() + { + ZeroMemory(m_aBitmap, sizeof m_aBitmap); + } + + CBitmap m_aBitmap[t_items]; + + // Operations + HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false) + { + ATLASSERT(uIndex < t_items); + + m_aBitmap[uIndex] = hbm; + + return bUpdate ? InvalidateItems() : S_OK; + } + +// Implementation + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_items); + + if (k_(key) == k_ItemImage) + { + if (m_aBitmap[uItem].IsNull()) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem); + } + return m_aBitmap[uItem].IsNull() ? + E_NOTIMPL : + SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value); + } + else + { + return TextCollection::DoGetItem(uItem, key, value); + } + } +}; + +// ComboCollectionImpl: handles combo text +// +template +class ComboCollectionImpl : public ItemCollectionImpl +{ + typedef ComboCollectionImpl thisClass; +public: + typedef thisClass ComboCollection; + + // Operations + HRESULT SetComboText(LPCWSTR sText) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + return ribbon.IsRibbonUI() ? + ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) : + S_OK; + } + + LPCWSTR GetComboText() + { + static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 }; + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + PROPVARIANT var; + if (ribbon.IsRibbonUI()) + { + HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var); + hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT); + return sCombo; + } + return NULL; + } +}; + +// CommandCollectionImpl: handles RibbonUI command collection controls +// +template +class CommandCollectionImpl : public CollectionImpl +{ + typedef CommandCollectionImpl thisClass; +public: + typedef thisClass CommandCollection; + + CommandCollectionImpl() + { + ZeroMemory(m_auCmd, sizeof m_auCmd); + ZeroMemory(m_aCmdType, sizeof m_aCmdType); + } + + UINT32 m_auCmd[t_items]; + BYTE m_aCmdType[t_items]; + + // Operations + HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false) + { + ATLASSERT(uItem < t_items); + + if (uCommandID == m_auCmd[uItem]) + return S_OK; + + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + + m_auCmd[uItem] = uCommandID; + if (uCommandID != 0) + ribbon.UIAddRibbonElement(uCommandID); + + return bUpdate ? InvalidateItems() : S_OK; + } + + HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false) + { + ATLASSERT(uItem < t_items); + + m_aCmdType[uItem] = (BYTE)type; + + return bUpdate ? InvalidateItems() : S_OK; + } + +// Implementation + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_items); + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + + HRESULT hr = E_FAIL; + switch (k_(key)) + { + case k_CommandId: + if (m_auCmd[uItem] == 0) + SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem)); + hr = SetPropertyVal(key, m_auCmd[uItem], value); + break; + case k_CommandType: + if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN) + SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem)); + hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); + break; + case k_CategoryId: + default: + hr = Collection::DoGetItem(uItem, key, value); + break; + } + + return hr; + } + + HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false) + { + ATLASSERT(FALSE); + return S_OK; + } +}; + +// SimpleCollectionImpl: collection class for ribbon simple collection controls +// +template +class SimpleCollectionImpl : public CollectionImplBase, t_size> +{ + typedef SimpleCollectionImpl thisClass; +public: + typedef CollectionImplBase CollectionBase; + typedef thisClass SimpleCollection; + +// Implementation + HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_size); + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_ItemImage: + if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem)) + hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value); + break; + case k_Label: + if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem)) + hr = SetPropertyVal(key, (LPCWSTR)sText, value); + break; + case k_CommandType: + hr = SetPropertyVal(key, t_CommandType, value); + break; + case k_CommandId: + hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value); + break; + case k_CategoryId: + hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon collection control classes + +// CollectionCtrlImpl: specializable class for ribbon collection controls +// +template +class CollectionCtrlImpl : public CommandCtrlImpl, public TCollection +{ + typedef CollectionCtrlImpl thisClass; +public: + typedef CommandCtrlImpl CommandCtrl; + typedef TCollection Collection; + + // Implementation + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == GetID()); + ATLASSERT(ppropvarNewValue); + + HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + if FAILED(hr) + hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + + return hr; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level4 warning + + if (key == NULL) // gallery button pressed + { + GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); + return S_OK; + } + + ATLASSERT(k_(*key) == k_SelectedItem); + ATLASSERT(ppropvarValue); + + HRESULT hr = S_OK; + UINT32 uSel = 0xffff; + hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); + + if (SUCCEEDED(hr)) + { + if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel)) + TCollection::Select(uSel); + } + + return hr; + } +}; + +// ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls +// +template +class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl, t_size>> +{ +public: + ToolbarGalleryCtrlImpl() + { + CResource tbres; + ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB)); + _AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock(); + ATLASSERT(pData); + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + INT j = 0; + for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++) + { + if (pItems[i] != 0) + { + m_aCmdType[j] = UI_COMMANDTYPE_ACTION; + m_auCmd[j++] = pItems[i]; + } + } + + if (j < t_size) + Resize(j); + } + + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < m_size); + ATLASSERT(m_auCmd[uItem]); + + HRESULT hr = E_FAIL; + switch (k_(key)) + { + case k_CommandId: + hr = SetPropertyVal(key, m_auCmd[uItem], value); + break; + case k_CommandType: + hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); + break; + case k_CategoryId: + hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } +}; + + +// SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls +// +template +class SimpleCollectionCtrlImpl : + public CommandCtrlImpl, + public SimpleCollectionImpl, t_size, t_CommandType> +{ + typedef SimpleCollectionCtrlImpl thisClass; +public: + typedef thisClass SimpleCollection; + + SimpleCollectionCtrlImpl() : m_uSelected(0) + { } + + UINT m_uSelected; + + HRESULT Select(UINT uItem, bool bUpdate = false) + { + ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX)); + + m_uSelected = uItem; + + return bUpdate ? + GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) : + S_OK; + } + + // Implementation + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == GetID()); + ATLASSERT(ppropvarNewValue != NULL); + + HRESULT hr = S_OK; + switch (k_(key)) + { + case k_ItemsSource: + { + ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); + ATLASSERT(pIUICollection.p); + hr = pIUICollection->Clear(); + for (UINT i = 0; i < t_size; i++) + { + if FAILED(hr = pIUICollection->Add(m_apItems[i])) + break; + } + ATLASSERT(SUCCEEDED(hr)); + } + break; + case k_SelectedItem: + hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue); + break; + default: + hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + + HRESULT hr = S_OK; + if (key == NULL) // gallery button pressed + { + GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); + return hr; + } + ATLASSERT(k_(*key) == k_SelectedItem); + ATLASSERT(ppropvarValue); + + if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected)) + GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected); + + return hr; + } +}; + +// RecentItemsCtrlImpl +// +template +class RecentItemsCtrlImpl : + public CtrlImpl, + public CollectionImplBase, TDocList::m_nMaxEntries_Max>, + public TDocList +{ + typedef RecentItemsCtrlImpl thisClass; +public: + typedef thisClass RecentItems; + + // Implementation + HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT((INT)uItem < GetMaxEntries()); + + LPCWSTR sPath = m_arrDocs[uItem].szDocName; + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_Label: + hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value); + break; + case k_LabelDescription: + hr = SetPropertyVal(key, sPath, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == GetID()); + ATLASSERT(ppropvarNewValue); + + HRESULT hr = S_OK; + switch (k_(key)) + { + case k_RecentItems: + if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize())) + { + const int iLastIndex = m_arrDocs.GetSize() - 1; + for (LONG i = 0; i <= iLastIndex; i++) + SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order + + hr = SetPropertyVal(key, psa, ppropvarNewValue); + SafeArrayDestroy(psa); + } + break; + default: + hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT(nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); + verb; // avoid level 4 warning + ATLASSERT((key) && (k_(*key) == k_SelectedItem)); + ATLASSERT(ppropvarValue); + + UINT32 uSel = 0xffff; + HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); + if SUCCEEDED(hr) + { + ATLASSERT(uSel < (UINT)GetMaxEntries()); + GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel); + } + + return hr; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon stand-alone control classes + +// FontCtrlImpl +// +template +class FontCtrlImpl : public CtrlImpl +{ +public: + + CharFormat m_cf; + +// Implementation + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT ((key) && (k_(*key) == k_FontProperties)); + key; // avoid level 4 warning + + HRESULT hr = E_INVALIDARG; + switch (verb) + { + case UI_EXECUTIONVERB_PREVIEW: + case UI_EXECUTIONVERB_EXECUTE: + ATLASSERT(pCommandExecutionProperties); + PROPVARIANT propvar; + + if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar))) + m_cf << ATL::CComQIPtr(propvar.punkVal); + break; + + case UI_EXECUTIONVERB_CANCELPREVIEW: + ATLASSERT(ppropvarValue); + ATL::CComPtr pStore; + + if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore))) + m_cf << pStore; + break; + } + + if (SUCCEEDED(hr)) + GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf); + else + ATLASSERT(FALSE); + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf))) + { + ATL::CComQIPtr pStore(ppropvarCurrentValue->punkVal); + m_cf >> pStore; + return SetPropertyVal(key, pStore.p, ppropvarNewValue); + } + else + { + return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } + } +}; + +// ColorCtrlImpl +// +template +class ColorCtrlImpl : public CommandCtrlImpl +{ +public: + ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/ + { } + + COLORREF m_color; + UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE + Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel + ATL::CSimpleArray m_aColors[2]; + ATL::CSimpleArray m_aTooltips[2]; + + // Operations + HRESULT SetColor(COLORREF color, bool bUpdate = false) + { + if (m_colorType != UI_SWATCHCOLORTYPE_RGB) + SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate); + m_color = color; + return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK; + } + + HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false) + { + m_colorType = type; + return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK; + } + + HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false) + { + ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel)); + m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel; + return bUpdate ? SetProperty(key, sLabel) : S_OK; + } + + HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false) + { + ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors)); + + const INT ic = k_(key) - k_ThemeColors; + m_aColors[ic].RemoveAll(); + while (*pColor != 0x800080) /*MAGENTA*/ + m_aColors[ic].Add(*pColor++); + + if (bUpdate) + { + PROPVARIANT var; + if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var)) + return SetProperty(key, var); + else + return E_INVALIDARG; + } + else + { + return S_OK; + } + } + + HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false) + { + ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips)); + + const INT ic = k_(key) - k_ThemeColorsTooltips; + m_aTooltips[ic].RemoveAll(); + while (*ppsTT) + m_aTooltips[ic].Add(*ppsTT++); + + if (bUpdate) + { + PROPVARIANT var; + if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var)) + return SetProperty(key, var); + else + return E_INVALIDARG; + } + else + { + return S_OK; + } + } + + // Implementation + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT (key && (k_(*key) == k_ColorType)); + key; // avoid level 4 warning + ATLASSERT (ppropvarValue); + + HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType); + ATLASSERT(SUCCEEDED(hr)); + + if (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB)) + { + ATLASSERT(pCommandExecutionProperties); + PROPVARIANT var; + if SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var)) + hr = PropVariantToUInt32(var, &m_color); + } + + if SUCCEEDED(hr) + GetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color); + else + ATLASSERT(FALSE); // something was wrong + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT (nCmdID == GetID()); + + HRESULT hr = E_NOTIMPL; + + switch (k_(key)) + { + case k_ColorType: + hr = SetPropertyVal(key, m_colorType, ppropvarNewValue); + break; + case k_Color: + if (m_color == 0x800080) /*MAGENTA*/ + m_color = GetWndRibbon().OnRibbonQueryColor(GetID()); + hr = SetPropertyVal(key, m_color, ppropvarNewValue); + break; + case k_ColorMode: + break; + case k_ThemeColorsCategoryLabel: + case k_StandardColorsCategoryLabel: + case k_RecentColorsCategoryLabel: + case k_AutomaticColorLabel: + case k_NoColorLabel: + case k_MoreColorsLabel: + { + const UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel; + if (m_sLabels[iLabel].IsEmpty()) + if (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key)) + m_sLabels[iLabel] = psLabel; + if (!m_sLabels[iLabel].IsEmpty()) + hr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue); + } + break; + case k_ThemeColors: + case k_StandardColors: + { + const INT ic = k_(key) - k_ThemeColors; + if (!m_aColors[ic].GetSize()) + if (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key)) + SetColorArray(key, pColor); + if (INT iMax = m_aColors[ic].GetSize()) + hr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue); + } + break; + case k_ThemeColorsTooltips: + case k_StandardColorsTooltips: + { + const INT ic = k_(key) - k_ThemeColorsTooltips; + if (m_aTooltips[ic].GetSize() == 0) + if (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key)) + SetColorTooltips(key, ppsTT); + if (INT iMax = m_aTooltips[ic].GetSize()) + hr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue); + } + break; + default: + hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } +}; + +// SpinnerCtrlImpl +// +template +class SpinnerCtrlImpl : public CtrlImpl +{ +public: + SpinnerCtrlImpl() + { + m_Values[0] = m_Values[2] = m_Values[4] = 0; + m_Values[1] = 100; + m_Values[3] = 1; + } + + V m_Values[5]; + // k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces + + Text m_FormatString; + Text m_RepresentativeString; + + // Operations + HRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false) + { + return SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate); + } + + HRESULT SetMin(V vMin, bool bUpdate = false) + { + return SetValue(UI_PKEY_MinValue, vMin, bUpdate); + } + + HRESULT SetMax(V vMax, bool bUpdate = false) + { + return SetValue(UI_PKEY_MaxValue, vMax, bUpdate); + } + + HRESULT SetVal(V vVal, bool bUpdate = false) + { + return SetValue(UI_PKEY_DecimalValue, vVal, bUpdate); + } + + HRESULT SetIncrement(V vIncrement, bool bUpdate = false) + { + return SetValue(UI_PKEY_Increment, vIncrement, bUpdate); + } + + HRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false) + { + return SetText(UI_PKEY_FormatString, sFormat, bUpdate); + } + + HRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false) + { + return SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate); + } + + // Implementation + HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false) + { + switch (k_(key)) + { + case k_FormatString: + m_FormatString = sText; + break; + case k_RepresentativeString: + m_RepresentativeString = sText; + break; + default: + return CtrlImpl::SetText(key, sText, bUpdate); + } + + return bUpdate ? + GetWndRibbon().InvalidateProperty(GetID(), key) : + S_OK; + } + + HRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false) + { + ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); + + const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; + m_Values[iVal] = val; + + if (bUpdate) + { + if(k_(key) == k_DecimalValue) + { + DECIMAL decVal; + InitDecimal(val, &decVal); + return SetProperty(key, &decVal); + } + else + { + return GetWndRibbon().InvalidateProperty(GetID(), key); + } + } + else + { + return S_OK; + } + } + + HRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal) + { + return GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal); + } + + HRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal) + { + return GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal); + } + + HRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv) + { + ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); + + const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; + + QueryValue(key, m_Values + iVal); + + if (k_(key) == k_DecimalPlaces) + { + return SetPropertyVal(key, m_Values[iVal], ppv); + } + else + { + DECIMAL decVal; + InitDecimal(m_Values[iVal], &decVal); + return SetPropertyVal(key, &decVal, ppv); + } + } + + HRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv) + { + if (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key)) + sVal = sNew; + return SetPropertyVal(key, (LPCWSTR)sVal, ppv); + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT (key && (k_(*key) == k_DecimalValue)); + key; // avoid level 4 warning + ATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE); + verb; // avoid level 4 warning + + DECIMAL decVal; + + HRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal); + hr = InitVal(m_Values[0], &decVal); + + GetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]); + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT (nCmdID == GetID()); + + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_DecimalPlaces: + case k_DecimalValue: + case k_Increment: + case k_MaxValue: + case k_MinValue: + hr = OnGetValue(key, ppropvarNewValue); + break; + case k_FormatString: + if (m_FormatString.IsEmpty()) + return OnGetText(key, m_FormatString, ppropvarNewValue); + break; + case k_RepresentativeString: + if (m_RepresentativeString.IsEmpty()) + return OnGetText(key, m_RepresentativeString, ppropvarNewValue); + break; + default: + hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } + + // decimal conversion helpers + static HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal) + { + return ::VarDecFromI4(val, pDecimal); + } + + static HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal) + { + return ::VarDecFromR8(val, pDecimal); + } + + static HRESULT InitVal(LONG& val, const DECIMAL* pDecimal) + { + return ::VarI4FromDec(pDecimal, &val); + } + + static HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal) + { + return ::VarR8FromDec(pDecimal, &val); + } +}; + +// CRibbonImpl Ribbon implementation class +// +template +class CRibbonImpl : + public CRibbonUpdateUI, + public ICtrl, + public IUIApplication, + public IUICommandHandler +{ + typedef CRibbonImpl thisClass; +public: + typedef thisClass Ribbon; + typedef T WndRibbon; + + CRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL) + { +#ifdef _DEBUG + m_cRef = 1; +#endif + pWndRibbon = static_cast(this); + HRESULT hr = ::CoInitialize(NULL); + if(SUCCEEDED(hr)) + if (RunTimeHelper::IsRibbonUIAvailable()) + hr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework); + else + ATLTRACE(L"Ribbon UI not available\n"); + + if FAILED(hr) + ATLTRACE(L"Ribbon construction failed\n"); + + ATLASSERT(SUCCEEDED(hr)); + } + + ~CRibbonImpl() + { + ::GlobalFree(m_hgRibbonSettings); + m_pIUIFramework.Release(); + ::CoUninitialize(); + } + + ICtrl& GetRibbonCtrl(UINT) + { + return static_cast(*this); + } + + ATL::CComPtr m_pIUIFramework; + HGLOBAL m_hgRibbonSettings; + bool m_bRibbonUI; + + bool IsRibbonUI() + { + return m_bRibbonUI; + } + + IUIFramework* GetIUIFrameworkPtr() + { + return m_pIUIFramework; + } + + template + I* GetRibbonViewPtr(UINT32 uID) + { + ATLASSERT(m_pIUIFramework); + ATL::CComPtr pI; + return m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ? + pI : + NULL; + } + + IUIRibbon* GetRibbonPtr() + { + return GetRibbonViewPtr(0); + } + + IUIContextualUI* GetMenuPtr(UINT32 uID) + { + ATLASSERT(uID); + return GetRibbonViewPtr(uID); + } + + UINT GetRibbonHeight() + { + ATLASSERT(IsRibbonUI()); + + UINT32 cy = 0; + if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) + pIUIRibbon->GetHeight(&cy); + return cy; + } + + HRESULT CreateRibbon(LPCWSTR sResName = L"APPLICATION_RIBBON") + { + T* pT = static_cast(this); + ATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI()); + ATLASSERT(pT->IsWindow()); + + HRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this); + + if (hr == S_OK) + hr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName); + + return hr; + } + + HRESULT DestroyRibbon() + { + T* pT = static_cast(this); + ATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI()); + ATLASSERT(pT->IsWindow()); + + HRESULT hRes = m_pIUIFramework->Destroy(); + if (!RunTimeHelper::IsWin7()) + pT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround + return hRes; + } + +// Ribbon persistency + HRESULT operator >>(IStream* pIStream) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(pIStream); + + HRESULT hr = E_FAIL; + if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) + { + const LARGE_INTEGER li0 = { 0 }; + pIStream->Seek(li0, STREAM_SEEK_SET, NULL); + hr = pIUIRibbon->SaveSettingsToStream(pIStream); + pIStream->Commit(STGC_DEFAULT); + } + + return hr; + } + + HRESULT operator <<(IStream* pIStream) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(pIStream); + + HRESULT hr = E_FAIL; + if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) + { + const LARGE_INTEGER li0 = { 0 }; + pIStream->Seek(li0, STREAM_SEEK_SET, NULL); + hr = pIUIRibbon->LoadSettingsFromStream(pIStream); + } + + return hr; + } + + void ResetRibbonSettings() + { + if (m_hgRibbonSettings != NULL) + { + ::GlobalFree(m_hgRibbonSettings); + m_hgRibbonSettings = NULL; + } + } + + HRESULT SaveRibbonSettings() + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(static_cast(this)->IsWindow()); + + HRESULT hr = E_FAIL; + ATL::CComPtr pIStream; + + if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) + hr = *this >> pIStream; + + if (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL)) + hr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings); + + if FAILED(hr) + ResetRibbonSettings(); + + return hr; + } + + HRESULT RestoreRibbonSettings() + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(m_hgRibbonSettings); + ATLASSERT(static_cast(this)->IsWindow()); + + HRESULT hr = E_FAIL; + ATL::CComPtr pIStream; + + if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) + hr = *this << pIStream; + + if FAILED(hr) + ResetRibbonSettings(); + + return hr; + } + +// QAT dock states + UI_CONTROLDOCK GetQATDock() + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + + UINT32 uDock = 0; + PROPVARIANT propvar; + ATL::CComQIPtrpIPS(GetRibbonPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) && + SUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock))) + return (UI_CONTROLDOCK)uDock; + + ATLASSERT(FALSE); // something was wrong + return (UI_CONTROLDOCK)0; + } + + bool SetQATDock(UI_CONTROLDOCK dockState) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + + PROPVARIANT propvar; + ATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar))); + + ATL::CComQIPtrpIPS(GetRibbonPtr()); + if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar))) + { + pIPS->Commit(); + return true; + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + +// Ribbon display states + bool GetRibbonDisplayState(REFPROPERTYKEY key) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); + + PROPVARIANT propvar; + ATL::CComQIPtrpIPS(GetRibbonPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) + { + BOOL bState = FALSE; + if SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState)) + return (bState != FALSE); + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + + bool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); + + PROPVARIANT propvar; + ATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar))); + + ATL::CComQIPtrpIPS(GetRibbonPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) + { + pIPS->Commit(); + return true; + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + + bool IsRibbonMinimized() + { + return GetRibbonDisplayState(UI_PKEY_Minimized); + } + + bool MinimizeRibbon(bool bMinimize = true) + { + return SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize); + } + + bool IsRibbonHidden() + { + return !GetRibbonDisplayState(UI_PKEY_Viewable); + } + + bool HideRibbon(bool bHide = true) + { + return SetRibbonDisplayState(UI_PKEY_Viewable, !bHide); + } + +// Ribbon colors + UI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); + + PROPVARIANT propvar; + ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) + { + UINT32 color = 0; + if SUCCEEDED(UIPropertyToUInt32(key, propvar, &color)) + return color; + } + + ATLASSERT(FALSE); // something was wrong + return 0; + } + + bool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); + + PROPVARIANT propvar; + ATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar))); + + ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) + { + pIPS->Commit(); + return true; + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + +// Ribbon modes + HRESULT SetRibbonModes(INT32 iModes) + { + ATLASSERT(IsRibbonUI()); + return GetIUIFrameworkPtr()->SetModes(iModes); + } + +// Ribbon contextual tab + UI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID) + { + ATLASSERT(GetIUIFrameworkPtr()); + + PROPVARIANT propvar; + if (IsRibbonUI() && + SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar))) + { + UINT uav; + if (SUCCEEDED(PropVariantToUInt32(propvar, &uav))) + { + CUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); + CUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE); + return (UI_CONTEXTAVAILABILITY)uav; + } + } + + return UI_CONTEXTAVAILABILITY_NOTAVAILABLE; + } + + HRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav) + { + CUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); + CUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE); + + return SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav)); + } + +// Ribbon context menu + bool HasRibbonMenu(UINT32 uID) + { + ATL::CComPtr pI = GetMenuPtr(uID); + return pI != NULL; + } + + HRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y) + { + ATLASSERT(HasRibbonMenu(uID)); + + return IsRibbonUI() ? + ATL::CComPtr(GetMenuPtr(uID))->ShowAtLocation(x, y) : + E_FAIL; + } + + HRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam) + { + return TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + +// Overrideables + HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/) + { + return DefRibbonQueryImage(nCmdID); + } + + LPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) + { + return DefRibbonQueryText(nCmdID, key); + } + + bool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) + { + return DefRibbonQueryState(nCmdID, key); + } + + UI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID) + { + DWORD dwState = UIGetState(nCmdID); + return ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ? + UI_CONTEXTAVAILABILITY_NOTAVAILABLE : + (((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ? + UI_CONTEXTAVAILABILITY_ACTIVE : + UI_CONTEXTAVAILABILITY_AVAILABLE); + } + + LPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/) + { + return NULL; + } + + LPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/) + { + return L"Category"; + } + + UINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) + { + return 0; + } + + LPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryItemText(uCtrlID, uItem); + } + + bool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/) + { + return false; + } + + HBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryItemImage(uCtrlID, uItem); + } + + UINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryItemCommand(uCtrlID, uItem); + } + + UI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) + { + return UI_COMMANDTYPE_ACTION; + } + + LPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath) + { + return ::PathFindFileName(sPath); + } + + bool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/) + { + return false; + } + + bool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/) + { + return false; + } + + bool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/) + { + return false; + } + + COLORREF OnRibbonQueryColor(UINT /*nCmdID*/) + { + return 0x800080; /*MAGENTA*/ + } + + LPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) + { + return NULL; + } + + COLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) + { + return NULL; + } + + LPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) + { + return NULL; + } + + bool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem) + { + DefCommandExecute(MAKELONG(uCtrlID, verb), uItem); + return true; + } + + void OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) + { + DefRibbonColorCtrlExecute(uCtrlID, verb, uType, color); + } + + void OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf) + { + DefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf); + } + + void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal) + { + DefCommandExecute(uCtrlID, *pVal); + } + + void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal) + { + DefCommandExecute(uCtrlID, (LPARAM)pVal); + } + + void OnRibbonCommandExecute(UINT32 uCmdID) + { + DefCommandExecute(uCmdID); + } + +// Default implementations + HBITMAP DefRibbonQueryImage(UINT nCmdID) + { + return AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION); + } + + bool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) + { + DWORD dwState = UIGetState(nCmdID); + bool bRet = false; + switch (k_(key)) + { + case k_BooleanValue: + bRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED; + break; + case k_Enabled: + bRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED; + break; + default: + ATLASSERT(FALSE); + break; + } + + return bRet; + } + + LPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) + { + static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; + + if (k_(key) == k_Label) + return UIGetText(nCmdID); + + if (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT)) + { + PWCHAR pTitle = wcschr(sText, L'\n'); + switch (k_(key)) + { + case k_Keytip: + if (PWCHAR pAmp = wcschr(sText, L'&')) + pTitle = pAmp; + if (pTitle != NULL) + *(pTitle + 2) = NULL; // fall through + case k_TooltipTitle: + return pTitle ? ++pTitle : NULL; + case k_TooltipDescription: + case k_LabelDescription: + if (pTitle != NULL) + *pTitle = NULL; + return sText; + } + } + + return NULL; + } + + LPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription); + } + + HBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryImage(uCtrlID + 1 + uItem); + } + + UINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) + { + return uCtrlID + 1 + uItem; + } + + void DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) + { + switch(uType) + { + case UI_SWATCHCOLORTYPE_RGB: + break; + case UI_SWATCHCOLORTYPE_AUTOMATIC: + color = ::GetSysColor(COLOR_WINDOWTEXT); + break; + case UI_SWATCHCOLORTYPE_NOCOLOR: + color = ::GetSysColor(COLOR_WINDOW); + break; + default: + ATLASSERT(FALSE); + break; + } + + DefCommandExecute(MAKELONG(uCtrlID, verb), color); + } + + void DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0) + { + static_cast(this)->PostMessage(WM_COMMAND, uCmd, lParam); + } + +// Elements setting helpers + HRESULT InvalidateCtrl(UINT32 nID) + { + return IsRibbonUI() ? + GetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) : + E_FAIL; + } + + HRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) + { + return IsRibbonUI() ? + GetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) : + E_FAIL; + } + + template + HRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val) + { + if (IsRibbonUI()) + { + PROPVARIANT var; + if (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var))) + { + return SetProperty(wID, key, var); + } + return E_INVALIDARG; + } + else + { + return E_FAIL; + } + } + + template <> + HRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var) + { + return IsRibbonUI() ? + GetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) : + E_FAIL; + } + +// Interfaces + // IUIApplication + STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32) + { + switch (verb) + { + case UI_VIEWVERB_CREATE: + m_bRibbonUI = true; + if (m_hgRibbonSettings != NULL) + RestoreRibbonSettings(); + break; + case UI_VIEWVERB_SIZE: + static_cast(this)->UpdateLayout(FALSE); + break; + case UI_VIEWVERB_DESTROY: + SaveRibbonSettings(); + m_bRibbonUI = false; + break; + } + + return S_OK; + } + + STDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler) + { + UIAddRibbonElement(nCmdID); + if (typeID == UI_COMMANDTYPE_CONTEXT) + CUpdateUIBase::UIEnable(nCmdID, false); + *ppCommandHandler = this; + return S_OK; + } + + STDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*) + { + UIRemoveRibbonElement(nCmdID); + return S_OK; + } + + // IUICommandHandler + STDMETHODIMP Execute(UINT nCmdID, + UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, + const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + T* pT =static_cast(this); + return pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); + } + + STDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + T* pT =static_cast(this); + return pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } + +#ifdef _DEBUG + // IUnknown methods (heavyweight) + STDMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + STDMETHODIMP_(ULONG) Release() + { + LONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) // NoOp for breakpoint + { + cRef = 0; + } + + return cRef; + } + + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if (ppv == NULL) + { + return E_POINTER; + } + else if ((iid == __uuidof(IUnknown)) || + (iid == __uuidof(IUICommandHandler)) || + (iid == __uuidof(IUIApplication))) + { + *ppv = this; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } + + LONG m_cRef; +#else + // IUnknown methods (lightweight) + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if ((iid == __uuidof(IUnknown)) || + (iid == __uuidof(IUICommandHandler)) || + (iid == __uuidof(IUIApplication))) + { + *ppv = this; + return S_OK; + } + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + ULONG STDMETHODCALLTYPE Release() + { + return 1; + } +#endif + +// CRibbonImpl ICtrl implementation + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + if (key != NULL) + { + if(k_(*key) != k_BooleanValue) + { + ATLTRACE(L"Control ID %d is not handled\n", nCmdID); + return E_NOTIMPL; + } + BOOL bChecked = FALSE; + ATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked))); + CUpdateUIBase::UISetCheck(nCmdID, bChecked); + } + + ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); + verb; // avoid level 4 warning + + static_cast(this)->OnRibbonCommandExecute(nCmdID); + + return S_OK; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue) + { + T* pT = static_cast(this); + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_LargeImage: + case k_LargeHighContrastImage: + case k_SmallImage: + case k_SmallHighContrastImage: + if (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key)) + hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue); + break; + case k_Label: + case k_Keytip: + case k_TooltipTitle: + case k_TooltipDescription: + case k_LabelDescription: + if (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key)) + hr = SetPropertyVal(key, sText, ppropvarNewValue); + break; + case k_BooleanValue: + case k_Enabled: + hr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue); + break; + case k_ContextAvailable: + hr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue); + break; + } + + return hr; + } + +// CRibbonImpl::CRibbonXXXCtrl specialized classes + //CRibbonComboCtrl + template + class CRibbonComboCtrl : public CollectionCtrlImpl, t_items, t_categories>> + { + public: + CRibbonComboCtrl() + { } + }; + + // CRibbonItemGalleryCtrl + template + class CRibbonItemGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> + { + public: + CRibbonItemGalleryCtrl() + { } + }; + + // CRibbonCommandGalleryCtrl + template + class CRibbonCommandGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> + { + public: + CRibbonCommandGalleryCtrl() + { } + }; + + // CRibbonToolbarGalleryCtrl + template + class CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl + { }; + + // CRibbonSimpleComboCtrl + template + class CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl + { }; + + // CRibbonSimpleGalleryCtrl + template + class CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl + { }; + + //CRibbonRecentItemsCtrl + template + class CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl + { + public: + CRibbonRecentItemsCtrl() + { } + }; + + // CRibbonColorCtrl + template + class CRibbonColorCtrl : public ColorCtrlImpl + { + public: + CRibbonColorCtrl() + { } + }; + + //CRibbonFontCtrl + template + class CRibbonFontCtrl : public FontCtrlImpl + { + public: + CRibbonFontCtrl() + { } + }; + + // CRibbonSpinnerCtrl + template + class CRibbonSpinnerCtrl : public SpinnerCtrlImpl + { + public: + CRibbonSpinnerCtrl() + { } + }; + + // CRibbonFloatSpinnerCtrl + template + class CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl + { + public: + CRibbonFloatSpinnerCtrl() + { + m_Values[4] = 1; // 1 decimal + } + }; + + // CRibbonCommandCtrl + template + class CRibbonCommandCtrl : public CommandCtrlImpl + { + public: + CRibbonCommandCtrl() + { } + }; + +// Control classes access to T instance (re-initialized in constructor) + static T* pWndRibbon; +}; + +template +__declspec(selectany) T* CRibbonImpl::pWndRibbon; + +// Control map element +#pragma warning (disable : 4510 610) // missing default constructor +typedef struct +{ + UINT uID; + ICtrl& ctrl; +} _ribbonCtrl; +#pragma warning (default : 4510 610) // missing default constructor + +}; // namespace RibbonUI + + +/////////////////////////////////////////////////////////////////////////////// +// RibbonUI Control map + +// Control map macros +#define BEGIN_RIBBON_CONTROL_MAP(theClass) \ + RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \ + { \ + RibbonUI::_ribbonCtrl _ctrls[] = \ + { + +#define RIBBON_CONTROL(member) {member.GetID(), static_cast(member)}, + +#define END_RIBBON_CONTROL_MAP() \ + {0, *this} \ + }; \ + int i = 0; \ + for(; i < _countof(_ctrls) - 1; i++) \ + if (_ctrls[i].uID == id) \ + break; \ + return _ctrls[i].ctrl; \ +} + +// Control message map macros +#define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_COMBO_CONTROL_HANDLER(id, func) \ + RIBBON_GALLERY_CONTROL_HANDLER(id, func) + +#define RIBBON_FONT_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_COLOR_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == wParam) \ + { \ + bHandled = TRUE; \ + lResult = func((WORD)wParam, (LONG)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == wParam) \ + { \ + bHandled = TRUE; \ + lResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +// Handler prototypes +/* + LRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); + LRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); + LRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled); + LRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled); + LRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled); + LRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled); +*/ + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon frame classes + +// CRibbonFrameWindowImplBase +// +template +class ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl +{ + typedef TFrameImpl baseFrame; + bool m_bUseCommandBarBitmaps; + bool m_bWin7Fix; + +public: +// Construction + CRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) : + m_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false) + { + __if_not_exists(T::m_CmdBar) + { + m_bUseCommandBarBitmaps = false; + } + } + +// Win7 Aero fix helpers + void ResetFrame() + { + const MARGINS margins = { 0 }; + ::DwmExtendFrameIntoClientArea(m_hWnd, &margins); + } + + INT CalcWin7Fix() + { + ResetFrame(); + RECT rc = { 0 }; + ::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0)); + return -rc.top; + } + + bool NeedWin7Fix() + { + BOOL bComp = FALSE; + return m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp; + } + +// Operations + bool UseCommandBarBitmaps(bool bUse) + { + __if_exists(T::m_CmdBar) + { + return m_bUseCommandBarBitmaps = bUse; + } + __if_not_exists(T::m_CmdBar) + { + bUse; // avoid level 4 warning + return false; + } + } + + bool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L"APPLICATION_RIBBON") + { + if (!RunTimeHelper::IsRibbonUIAvailable()) + return false; + + ATLASSERT(GetIUIFrameworkPtr()); + + if (IsRibbonUI() == bShow) + return bShow; + + bool bVisible = (IsWindowVisible() != FALSE); + if(bVisible && !bShow) + SetRedraw(FALSE); + + if (bShow && ::IsWindow(m_hWndToolBar)) + { + ::ShowWindow(m_hWndToolBar, SW_HIDE); + UpdateLayout(); + } + + m_bWin7Fix = !bShow; + + HRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon(); + + m_bWin7Fix = SUCCEEDED(hr) && !bShow; + + if (SUCCEEDED(hr)) + { + if(::IsWindow(m_hWndToolBar) && !bShow) + { + ::ShowWindow(m_hWndToolBar, SW_SHOWNA); + UpdateLayout(); + } + else if (bShow) + { + PostMessage(WM_SIZE); + SetRibbonModes(imodes); + } + } + + if(bVisible && !bShow) + { + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + + return SUCCEEDED(hr) ? bShow : !bShow; + } + +// Overrideables + HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key) + { + if ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps) + { + if (HBITMAP hbm = GetCommandBarBitmap(nCmdID)) + return (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + } + + return DefRibbonQueryImage(nCmdID); + } + + BEGIN_MSG_MAP(CRibbonFrameWindowImplBase) + if (!IsRibbonUI() && NeedWin7Fix()) + { + MESSAGE_HANDLER(WM_SIZING, OnSizing) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + MESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize) + } + CHAIN_MSG_MAP(CRibbonUpdateUI) + CHAIN_MSG_MAP(baseFrame) + END_MSG_MAP() + +// Message handlers for Win7 Aero + LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + switch (wParam) + { + case WMSZ_TOP: + case WMSZ_TOPLEFT: + case WMSZ_TOPRIGHT: + SetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + break; + default: + DefWindowProc(); + break; + } + + return 1; // handled + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if (wParam != SIZE_MINIMIZED) + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + bHandled = FALSE; + return 1; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != WA_INACTIVE) + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + bHandled = FALSE; + return 1; + } + + LRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + ATLASSERT(!IsRibbonUI() && NeedWin7Fix()); + + LRESULT lRet = DefWindowProc(); + + if(wParam) + { + LPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam; + pParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix(); + } + + return lRet; + } + +// Overrides + void UpdateLayout(BOOL bResizeBars = TRUE) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + if (IsRibbonUI() && !IsRibbonHidden()) + { + rect.top += GetRibbonHeight(); + } + else if (!IsRibbonUI() && NeedWin7Fix()) + { + ResetFrame(); + } + + // 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); + } + + // Implementation + HBITMAP GetCommandBarBitmap(UINT nCmdID) + { + __if_exists (T::m_CmdBar) + { + ATLASSERT(RunTimeHelper::IsVista()); + T* pT =static_cast(this); + int nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID); + return (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex]; + } + __if_not_exists (T::m_CmdBar) + { + nCmdID; // avoid level 4 warning + return NULL; + } + } +}; + +// CRibbonFrameWindowImpl +// +template +class ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase> +{ }; + +// CRibbonMDIFrameWindowImpl +// +template +class ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase> +{ }; + + +/////////////////////////////////////////////////////////////////////////////// +// CRibbonPersist helper for RibbonUI persistency + +class CRibbonPersist +{ +public: + CRibbonPersist(LPCWSTR sAppKey) + { + ATLASSERT(sAppKey && *sAppKey); + m_Key.Create(HKEY_CURRENT_USER, sAppKey); + ATLASSERT(m_Key.m_hKey); + } + + CRegKeyEx m_Key; + + LONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL) + { + CRegKeyEx key; + const DWORD dwUI = bRibbonUI; + + LONG lRet = key.Create(m_Key, L"Ribbon"); + if(lRet != ERROR_SUCCESS) + return lRet; + + lRet = key.SetDWORDValue(L"UI", dwUI); + if(lRet != ERROR_SUCCESS) + return lRet; + + if (hgSettings != NULL) + { + LPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings); + if (pVal != NULL) + { + lRet = key.SetBinaryValue(L"Settings", pVal, (ULONG)::GlobalSize(hgSettings)); + ::GlobalUnlock(hgSettings); + } + else + { + lRet = GetLastError(); + } + } + + return lRet; + } + + LONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings) + { + ATLASSERT(hgSettings == NULL); + + CRegKeyEx key; + + LONG lRet = key.Open(m_Key, L"Ribbon"); + if(lRet != ERROR_SUCCESS) + return lRet; + + DWORD dwUI = 0xffff; + lRet = key.QueryDWORDValue(L"UI", dwUI); + if(lRet == ERROR_SUCCESS) + bRibbonUI = dwUI == 1; + else + return lRet; + + ULONG ulSize = 0; + lRet = key.QueryBinaryValue(L"Settings", NULL, &ulSize); + if (lRet == ERROR_SUCCESS) + { + ATLASSERT(ulSize != 0); + + hgSettings = ::GlobalAlloc(GHND, ulSize); + if (hgSettings != NULL) + { + LPBYTE pData = (LPBYTE)::GlobalLock(hgSettings); + if (pData != NULL) + { + lRet = key.QueryBinaryValue(L"Settings", pData, &ulSize); + } + else + { + lRet = GetLastError(); + ::GlobalFree(hgSettings); + hgSettings = NULL; + } + } + else + { + lRet = GetLastError(); + } + } + return lRet; + } + + LONG Delete() + { + return m_Key.DeleteSubKey(L"Ribbon"); + } +}; + +} // namespace WTL + +#endif // __ATLRIBBON_H__ diff --git a/wtl/wtl/include/atlscrl.h b/wtl/wtl/include/atlscrl.h new file mode 100644 index 00000000..33ea3736 --- /dev/null +++ b/wtl/wtl/include/atlscrl.h @@ -0,0 +1,2007 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 + + +/////////////////////////////////////////////////////////////////////////////// +// 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..f94fa099 --- /dev/null +++ b/wtl/wtl/include/atlsplit.h @@ -0,0 +1,917 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 +#define SPLIT_GRADIENTBAR 0x00000008 +#define SPLIT_FIXEDBARSIZE 0x00000010 + +// 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(4), 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 = { 0 }; + if(GetSplitterBarRect(&rect)) + { + dc.FillRect(&rect, COLOR_3DFACE); + +#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420)) + if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0) + { + RECT rect2 = rect; + if(t_bVertical) + rect2.left = (rect.left + rect.right) / 2 - 1; + else + rect2.top = (rect.top + rect.bottom) / 2 - 1; + + dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), t_bVertical); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + + // 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 = { 0 }; + 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) + { + T* pT = static_cast(this); + pT->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 = { 0 }; + 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*/) + { + T* pT = static_cast(this); + pT->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 }; + 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 }; + if(GetSplitterBarRect(&rect)) + { + // convert client to window coordinates + T* pT = static_cast(this); + RECT rcWnd = { 0 }; + pT->GetWindowRect(&rcWnd); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2); + ::OffsetRect(&rect, -rcWnd.left, -rcWnd.top); + + // invert the brush pattern (looks just like frame window sizing) + 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) + { + if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0) + { +#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..ff7ee598 --- /dev/null +++ b/wtl/wtl/include/atltheme.h @@ -0,0 +1,1218 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 + +#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 + #ifndef TMSCHEMA_H + #include + #endif +#endif + +#ifndef _UXTHEME_H_ +#include +#endif +#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..6cd8205a --- /dev/null +++ b/wtl/wtl/include/atluser.h @@ -0,0 +1,1391 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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() +// +// AtlLoadAccelerators() +// AtlLoadMenu() +// AtlLoadBitmap() +// AtlLoadSysBitmap() +// AtlLoadCursor() +// AtlLoadSysCursor() +// AtlLoadIcon() +// AtlLoadSysIcon() +// AtlLoadBitmapImage() +// AtlLoadCursorImage() +// AtlLoadIconImage() +// AtlLoadSysBitmapImage() +// AtlLoadSysCursorImage() +// AtlLoadSysIconImage() +// AtlLoadString() + + +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 + +#elif (_ATL_VER >= 0x0800) + int GetMenuItemCount() const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuItemCount(m_hMenu); + } + + UINT GetMenuItemID(int nPos) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuItemID(m_hMenu, nPos); + } + + UINT GetMenuState(UINT nID, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuState(m_hMenu, nID, nFlags); + } + + int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); + } + + int GetMenuStringLen(UINT nIDItem, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags); + } +#endif // (_ATL_VER >= 0x0800) + +#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; + } + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Toolbar resource descriptor + +struct _AtlToolBarData +{ + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + + WORD* items() + { return (WORD*)(this+1); } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// 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(ModuleHelper::GetResourceInstance(), uID, lpBuffer, nBufferMax); +} +#else + +using ATL::AtlLoadString; + +#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; +} + +}; // 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..a8459492 --- /dev/null +++ b/wtl/wtl/include/atlwince.h @@ -0,0 +1,2987 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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 +#endif + +#if (_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); + if (nTitleHeight) + lpRect->top += nTitleHeight + 1; + 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; + + void CheckStyle() + { + // Mobile devices don't support DLGTEMPLATEEX + ATLASSERT(!m_Template.IsTemplateEx()); + + // Standard dialogs need only DS_CENTER + DWORD &dwStyle = m_Template.GetTemplatePtr()->style; + if (dwStyle & DS_CENTER) + if(t_bModal) + { + ATLASSERT((dwStyle & WS_CHILD) != WS_CHILD); + dwStyle |= WS_POPUP; + } + else + { + if((dwStyle & WS_CHILD) != WS_CHILD) + dwStyle |= WS_POPUP; + } + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) + { + ATLASSERT(t_bModal); + + if (!m_Template.IsValid()) + CreateTemplate(); + + CheckStyle(); + + return _baseClass::DoModal(hWndParent, dwInitParam); + } + + HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) + { + ATLASSERT(!t_bModal); + + if (!m_Template.IsValid()) + CreateTemplate(); + + CheckStyle(); + + 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: + CRegKeyEx 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 m_Key.SetBinaryValue(sName.m_lpstr, &val, sizeof(V)); + } + + template + LONG Save(int nb, V& val0, ATL::_U_STRINGorID sName) + { + return m_Key.SetBinaryValue(sName.m_lpstr, &val0, nb * sizeof(V)); + } + + template + LONG Restore(V& val, ATL::_U_STRINGorID sName) + { + ULONG bufSize = sizeof(V); + return m_Key.QueryBinaryValue(sName.m_lpstr, &val, &bufSize); + } + + template + LONG Restore(int nb, V& val0, ATL::_U_STRINGorID sName) + { + ULONG bufSize = nb * sizeof(V); + return m_Key.QueryBinaryValue(sName.m_lpstr, &val0, &bufSize); + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + 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; + } +#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__) + + 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); + } + + 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); + } + + void Undo() + { + UndoEvent(); + } + +// Standard EM_xxx messages + DWORD GetSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); + } + + void GetSel(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + } + + void SetSel(int nStartChar, int nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + ::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) + SecureHelper::strncpy_x(m_szPath, MAX_PATH, 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; + int cchLen = lstrlen(pstrTipText) + 3; + LPTSTR pstr = buff.Allocate(cchLen); + if(pstr == NULL) + return FALSE; + SecureHelper::strcpy_x(pstr, cchLen, _T("~~")); + SecureHelper::strcat_x(pstr, cchLen, 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; + int cchLen = lstrlen(pstrTipText) + 3; + LPTSTR pstr = buff.Allocate(cchLen); + if(pstr == NULL) + return FALSE; + SecureHelper::strcpy_x(pstr, cchLen, _T("~~")); + SecureHelper::strcat_x(pstr, cchLen, 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..629d2977 --- /dev/null +++ b/wtl/wtl/include/atlwinx.h @@ -0,0 +1,525 @@ +// Windows Template Library - WTL version 8.1 +// 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/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 __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__ diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h new file mode 100644 index 00000000..f9713fe5 --- /dev/null +++ b/wtl/wtl/include/multisplit.h @@ -0,0 +1,1048 @@ +/**************************************************************************** + * * + * 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; + } + + CMultiSplitPane* remove(void) + { + if( this->isSplitBar() ) + return 0; + + if( this->parent ) + { + CMultiSplitPane* survivor = + this->window == this->parent->pane0->window? + this->parent->pane1: + this->parent->pane0; + + ::SetWindowPos( + this->window, + 0, + 0, + 0, + 0, + 0, + SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER); + + // parent = survivor + CMultiSplitPane* result = this->parent; + result->window = survivor->window; + result->splitType = survivor->splitType; + result->splitRatio = survivor->splitRatio; + result->pane0 = survivor->pane0; + if( result->pane0 ) + result->pane0->parent = result; + result->pane1 = survivor->pane1; + if( result->pane1 ) + result->pane1->parent = result; + + // resize parent + result->resize(result->width, result->height); + + // delete the two children of the parent + 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; + } + + return 0; + } + + 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)); + } + } +#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) + { + 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)); + +#if 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); +#endif + + 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) + 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 ) + { + 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 + //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); + + 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; + } + + void SetDefaultFocusPane(CMultiSplitPane* newDefaultPane) + { + bool boolNotify = newDefaultPane != this->defaultFocusPane; + this->defaultFocusPane = newDefaultPane; + if( newDefaultPane && ::IsWindow(newDefaultPane->window) ) + ::SetFocus(newDefaultPane->window); + if( boolNotify ) + this->OnPaneChanged(); + } + + virtual void OnPaneChanged(void) + { + } + + 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__