diff --git a/HexCtrl/res/HexCtrl.rc b/HexCtrl/res/HexCtrl.rc index 75f16aa..0374bac 100644 --- a/HexCtrl/res/HexCtrl.rc +++ b/HexCtrl/res/HexCtrl.rc @@ -35,6 +35,12 @@ BEGIN "#include ""winres.h""\0" END +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + #endif // APSTUDIO_INVOKED @@ -88,8 +94,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,130,41,50,14 LTEXT "<--Version-->",IDC_HEXCTRL_ABOUT_STAT_VERSION,41,10,138,16 CONTROL "",IDC_HEXCTRL_ABOUT_LOGO,"Static",SS_BITMAP | SS_CENTERIMAGE,13,10,23,23 - CONTROL "https://github.com/jovibor/HexCtrl",IDC_HEXCTRL_ABOUT_LINKGITHUB, - "MfcLink",WS_TABSTOP,40,26,116,11 + LTEXT "https://github.com/jovibor/HexCtrl",IDC_HEXCTRL_ABOUT_STAT_LINKGH,41,26,113,8 END IDD_HEXCTRL_OPERS DIALOGEX 0, 0, 251, 106 @@ -308,23 +313,6 @@ IDB_HEXCTRL_FONTCHOOSE BITMAP "IDB_HEXCTRL_FONTCHOOSE.bmp" // Dialog Info // -IDD_HEXCTRL_ABOUT DLGINIT -BEGIN - IDC_HEXCTRL_ABOUT_LINKGITHUB, 0x37c, 191, 0 -0x4d3c, 0x4346, 0x694c, 0x6b6e, 0x555f, 0x6c72, 0x683e, 0x7474, 0x7370, -0x2f3a, 0x672f, 0x7469, 0x7568, 0x2e62, 0x6f63, 0x2f6d, 0x6f6a, 0x6976, -0x6f62, 0x2f72, 0x6548, 0x4378, 0x7274, 0x3c6c, 0x4d2f, 0x4346, 0x694c, -0x6b6e, 0x555f, 0x6c72, 0x3c3e, 0x464d, 0x4c43, 0x6e69, 0x5f6b, 0x7255, -0x506c, 0x6572, 0x6966, 0x3e78, 0x2f3c, 0x464d, 0x4c43, 0x6e69, 0x5f6b, -0x7255, 0x506c, 0x6572, 0x6966, 0x3e78, 0x4d3c, 0x4346, 0x694c, 0x6b6e, -0x545f, 0x6f6f, 0x746c, 0x7069, 0x3c3e, 0x4d2f, 0x4346, 0x694c, 0x6b6e, -0x545f, 0x6f6f, 0x746c, 0x7069, 0x3c3e, 0x464d, 0x4c43, 0x6e69, 0x5f6b, -0x7546, 0x6c6c, 0x6554, 0x7478, 0x6f54, 0x6c6f, 0x6974, 0x3e70, 0x4146, -0x534c, 0x3c45, 0x4d2f, 0x4346, 0x694c, 0x6b6e, 0x465f, 0x6c75, 0x546c, -0x7865, 0x5474, 0x6f6f, 0x746c, 0x7069, "\076" - 0 -END - IDD_HEXCTRL_DATAINTERP DLGINIT BEGIN IDC_HEXCTRL_DATAINTERP_GRID, 0x37c, 414, 0 @@ -557,3 +545,14 @@ IDJ_HEXCTRL_KEYBIND JSON "IDJ_HEXCTRL_KEYBIND.json" ///////////////////////////////////////////////////////////////////////////// + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/HexCtrl/res/HexCtrlRes.h b/HexCtrl/res/HexCtrlRes.h index 95a8208..26d2039 100644 --- a/HexCtrl/res/HexCtrlRes.h +++ b/HexCtrl/res/HexCtrlRes.h @@ -48,7 +48,7 @@ #define IDC_HEXCTRL_SEARCH_LIST 9044 #define IDC_HEXCTRL_SEARCH_STAT_RESULT 9045 #define IDC_HEXCTRL_ABOUT_STAT_VERSION 9046 -#define IDC_HEXCTRL_ABOUT_LINKGITHUB 9047 +#define IDC_HEXCTRL_ABOUT_STAT_LINKGH 9047 #define IDC_HEXCTRL_ABOUT_LOGO 9048 #define IDC_HEXCTRL_MODIFY_TAB 9049 #define IDC_HEXCTRL_OPERS_COMBO_OPER 9050 diff --git a/HexCtrl/src/CHexCtrl.cpp b/HexCtrl/src/CHexCtrl.cpp index ee6225a..f0cc71d 100644 --- a/HexCtrl/src/CHexCtrl.cpp +++ b/HexCtrl/src/CHexCtrl.cpp @@ -48,46 +48,174 @@ CWinApp theApp; //CWinApp object is vital for manual MFC, and for in-DLL work. #endif namespace HEXCTRL::INTERNAL { - class CHexDlgAbout final : public CDialogEx { + class CHexDlgAbout final { public: - explicit CHexDlgAbout(CWnd* pParent) : CDialogEx(IDD_HEXCTRL_ABOUT, pParent) { } + CHexDlgAbout(HWND hWndParent = nullptr) { m_hWndParent = hWndParent; } + auto DoModal() -> INT_PTR; + [[nodiscard]] auto ProcessMsg(const MSG& stMsg) -> INT_PTR; private: - afx_msg void OnDestroy() { - DeleteObject(m_bmpLogo); - CDialogEx::OnDestroy(); - }; - BOOL OnInitDialog()override; - DECLARE_MESSAGE_MAP() + auto OnCommand(const MSG& stMsg) -> INT_PTR; + auto OnCtlClrStatic(const MSG& stMsg) -> INT_PTR; + auto OnDestroy() -> INT_PTR; + auto OnInitDialog(const MSG& stMsg) -> INT_PTR; + auto OnLButtonDown(const MSG& stMsg) -> INT_PTR; + auto OnLButtonUp(const MSG& stMsg) -> INT_PTR; + auto OnMouseMove(const MSG& stMsg) -> INT_PTR; private: - HBITMAP m_bmpLogo { }; //Logo bitmap. + HWND m_hWnd { }; + HWND m_hWndParent { }; + HWND m_hWndLink { }; + HBITMAP m_hBmpLogo { }; //Logo bitmap. + HFONT m_hFontDef { }; + HFONT m_hFontUnderline { }; + bool m_fLinkUnderline { }; + bool m_fLBDownLink { }; //Left button was pressed on the link static control. }; } -BEGIN_MESSAGE_MAP(CHexDlgAbout, CDialogEx) - ON_WM_DESTROY() -END_MESSAGE_MAP() +auto CHexDlgAbout::DoModal()->INT_PTR { + return DialogBoxParamW(wnd::GetHinstance(), MAKEINTRESOURCEW(IDD_HEXCTRL_ABOUT), + m_hWndParent, wnd::DlgWndProc, reinterpret_cast(this)); +} + +auto CHexDlgAbout::ProcessMsg(const MSG& stMsg)->INT_PTR { + switch (stMsg.message) { + case WM_COMMAND: return CHexDlgAbout::OnCommand(stMsg); + case WM_CTLCOLORSTATIC: return CHexDlgAbout::OnCtlClrStatic(stMsg); + case WM_DESTROY: return CHexDlgAbout::OnDestroy(); + case WM_INITDIALOG: return CHexDlgAbout::OnInitDialog(stMsg); + case WM_LBUTTONDOWN: return CHexDlgAbout::OnLButtonDown(stMsg); + case WM_LBUTTONUP: return CHexDlgAbout::OnLButtonUp(stMsg); + case WM_MOUSEMOVE: return CHexDlgAbout::OnMouseMove(stMsg); + default: + return 0; + } +} -BOOL CHexDlgAbout::OnInitDialog() +auto CHexDlgAbout::OnCommand(const MSG& stMsg)->INT_PTR { + switch (LOWORD(stMsg.wParam)) { + case IDOK: + case IDCANCEL: + ::EndDialog(m_hWnd, IDOK); + return TRUE; + default: + return FALSE; + } +} + +auto CHexDlgAbout::OnCtlClrStatic(const MSG& stMsg)->INT_PTR { - CDialogEx::OnInitDialog(); + const auto hWndFrom = reinterpret_cast(stMsg.lParam); + if (hWndFrom == m_hWndLink) { + const auto hDC = reinterpret_cast(stMsg.wParam); + ::SetTextColor(hDC, RGB(0, 50, 250)); + ::SetBkColor(hDC, GetSysColor(COLOR_BTNFACE)); + ::SelectObject(hDC, m_fLinkUnderline ? m_hFontUnderline : m_hFontDef); + return reinterpret_cast(::GetStockObject(HOLLOW_BRUSH)); + } + + return FALSE; //Default handler. +} + +auto CHexDlgAbout::OnDestroy()->INT_PTR { + ::DeleteObject(m_hBmpLogo); + ::DeleteObject(m_hFontDef); + ::DeleteObject(m_hFontUnderline); + return TRUE; +}; + +auto CHexDlgAbout::OnInitDialog(const MSG& stMsg)->INT_PTR +{ + m_hWnd = stMsg.hwnd; + m_hWndLink = GetDlgItem(m_hWnd, IDC_HEXCTRL_ABOUT_STAT_LINKGH); + SetClassLongPtrW(m_hWnd, GCLP_HCURSOR, 0); //To prevent cursor blinking. + + if (const auto hFont = reinterpret_cast(::SendMessageW(m_hWndLink, WM_GETFONT, 0, 0)); hFont) { + m_hFontDef = hFont; + LOGFONTW lf { }; + ::GetObjectW(hFont, sizeof(lf), &lf); + lf.lfUnderline = TRUE; + m_hFontUnderline = ::CreateFontIndirectW(&lf); + } + else { + LOGFONTW lf { }; + ::GetObjectW(static_cast(::GetStockObject(DEFAULT_GUI_FONT)), sizeof(lf), &lf); + m_hFontDef = ::CreateFontIndirectW(&lf); + lf.lfUnderline = TRUE; + m_hFontUnderline = ::CreateFontIndirectW(&lf); + } const auto wstrVersion = std::format(L"Hex Control for Windows apps, v{}.{}.{}\r\nCopyright © 2018-present Jovibor", HEXCTRL_VERSION_MAJOR, HEXCTRL_VERSION_MINOR, HEXCTRL_VERSION_PATCH); - GetDlgItem(IDC_HEXCTRL_ABOUT_STAT_VERSION)->SetWindowTextW(wstrVersion.data()); + ::SetWindowTextW(GetDlgItem(m_hWnd, IDC_HEXCTRL_ABOUT_STAT_VERSION), wstrVersion.data()); - auto pDC = GetDC(); - const auto iLOGPIXELSY = GetDeviceCaps(pDC->m_hDC, LOGPIXELSY); - ReleaseDC(pDC); + auto hDC = ::GetDC(m_hWnd); + const auto iLOGPIXELSY = ::GetDeviceCaps(hDC, LOGPIXELSY); + ::ReleaseDC(m_hWnd, hDC); const auto fScale = iLOGPIXELSY / 96.0F; //Scale factor for HighDPI displays. const auto iSizeIcon = static_cast(32 * fScale); - m_bmpLogo = static_cast(LoadImageW(AfxGetInstanceHandle(), - MAKEINTRESOURCEW(IDB_HEXCTRL_LOGO), IMAGE_BITMAP, iSizeIcon, iSizeIcon, LR_CREATEDIBSECTION)); - static_cast(GetDlgItem(IDC_HEXCTRL_ABOUT_LOGO))->SetBitmap(m_bmpLogo); + m_hBmpLogo = static_cast(::LoadImageW(wnd::GetHinstance(), MAKEINTRESOURCEW(IDB_HEXCTRL_LOGO), + IMAGE_BITMAP, iSizeIcon, iSizeIcon, LR_CREATEDIBSECTION)); + const auto hWndStatic = ::GetDlgItem(m_hWnd, IDC_HEXCTRL_ABOUT_LOGO); + ::SendMessageW(hWndStatic, STM_SETIMAGE, IMAGE_BITMAP, reinterpret_cast(m_hBmpLogo)); return TRUE; } +auto CHexDlgAbout::OnLButtonDown(const MSG& stMsg)->INT_PTR +{ + const POINT pt { .x { GET_X_LPARAM(stMsg.lParam) }, .y { GET_Y_LPARAM(stMsg.lParam) } }; + const auto hWnd = ::ChildWindowFromPoint(m_hWnd, pt); + if (hWnd != m_hWndLink) { + m_fLBDownLink = false; + return FALSE; + } + + m_fLBDownLink = true; + + return TRUE; +} + +auto CHexDlgAbout::OnLButtonUp(const MSG& stMsg) -> INT_PTR +{ + const POINT pt { .x { GET_X_LPARAM(stMsg.lParam) }, .y { GET_Y_LPARAM(stMsg.lParam) } }; + const auto hWnd = ::ChildWindowFromPoint(m_hWnd, pt); + if (hWnd != m_hWndLink) { + m_fLBDownLink = false; + return FALSE; + } + + if (m_fLBDownLink) { + wchar_t buff[64]; + ::GetWindowTextW(m_hWndLink, buff, std::size(buff)); + ::ShellExecuteW(nullptr, L"open", buff, nullptr, nullptr, 0); + } + + return TRUE; +} + +auto CHexDlgAbout::OnMouseMove(const MSG& stMsg)->INT_PTR +{ + const POINT pt { .x { GET_X_LPARAM(stMsg.lParam) }, .y { GET_Y_LPARAM(stMsg.lParam) } }; + const auto hWnd = ::ChildWindowFromPoint(m_hWnd, pt); + if (hWnd == nullptr) + return FALSE; + + const auto curHand = reinterpret_cast(::LoadImageW(nullptr, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_SHARED)); + const auto curArrow = reinterpret_cast(::LoadImageW(nullptr, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED)); + + if (m_fLinkUnderline != (m_hWndLink == hWnd)) { + m_fLinkUnderline = m_hWndLink == hWnd; + ::InvalidateRect(m_hWndLink, nullptr, FALSE); + ::SetCursor(m_fLinkUnderline ? curHand : curArrow); + } + + return TRUE; +} + +//CHexCtrl. + enum class CHexCtrl::EClipboard : std::uint8_t { COPY_HEX, COPY_HEXLE, COPY_HEXFMT, COPY_BASE64, COPY_CARR, COPY_GREPHEX, COPY_PRNTSCRN, COPY_OFFSET, COPY_TEXT_CP, @@ -245,7 +373,7 @@ bool CHexCtrl::Create(const HEXCREATE& hcs) return false; } - const auto hInst = AfxGetInstanceHandle(); + const auto hInst = wnd::GetHinstance(); const auto fScale = m_iLOGPIXELSY / 96.0F; //Scale factor for HighDPI displays. const auto iSizeIcon = static_cast(16 * fScale); const auto pMenuTop = m_menuMain.GetSubMenu(0); //Context sub-menu handle. @@ -555,7 +683,7 @@ void CHexCtrl::ExecuteCmd(EHexCmd eCmd) break; case CMD_ABOUT_DLG: { - CHexDlgAbout dlgAbout(this); + CHexDlgAbout dlgAbout(m_hWnd); dlgAbout.DoModal(); } break; @@ -1653,7 +1781,7 @@ bool CHexCtrl::SetConfig(std::wstring_view wsvPath) rapidjson::Document docJSON; if (wsvPath.empty()) { //Default IDR_HEXCTRL_JSON_KEYBIND.json, from resources. - const auto hInst = AfxGetInstanceHandle(); + const auto hInst = wnd::GetHinstance(); if (const auto hRes = FindResourceW(hInst, MAKEINTRESOURCEW(IDJ_HEXCTRL_KEYBIND), L"JSON"); hRes != nullptr) { if (const auto hData = LoadResource(hInst, hRes); hData != nullptr) { const auto nSize = static_cast(SizeofResource(hInst, hRes)); @@ -3981,28 +4109,23 @@ void CHexCtrl::ParentNotify(UINT uCode)const void CHexCtrl::Print() { - CPrintDialogEx dlg(PD_RETURNDC | (HasSelection() ? PD_SELECTION : PD_NOSELECTION | PD_PAGENUMS), this); - dlg.m_pdex.lStructSize = sizeof(PRINTDLGEX); - dlg.m_pdex.nStartPage = START_PAGE_GENERAL; - dlg.m_pdex.nMinPage = 1; - dlg.m_pdex.nMaxPage = 0xFFFFUL; - dlg.m_pdex.nPageRanges = 1; - dlg.m_pdex.nMaxPageRanges = 1; - PRINTPAGERANGE ppr { .nFromPage = 1, .nToPage = 1 }; - dlg.m_pdex.lpPageRanges = &ppr; - - if (dlg.DoModal() != S_OK) { + PRINTPAGERANGE ppr { .nFromPage { 1 }, .nToPage { 1 } }; + PRINTDLGEX m_pdex { .lStructSize { sizeof(PRINTDLGEX) }, .hwndOwner { m_hWnd }, + .Flags { static_cast(PD_RETURNDC | (HasSelection() ? PD_SELECTION : PD_NOSELECTION | PD_PAGENUMS)) }, + .nPageRanges { 1 }, .nMaxPageRanges { 1 }, .lpPageRanges { &ppr }, .nMinPage { 1 }, .nMaxPage { 0xFFFFUL }, + .nStartPage { START_PAGE_GENERAL } }; + + if (PrintDlgExW(&m_pdex) != S_OK) { MessageBoxW(L"Internal printer initialization error.", L"Error", MB_ICONERROR); return; } - //User pressed "Cancel", or "Apply" and then "Cancel". - if (dlg.m_pdex.dwResultAction == PD_RESULT_CANCEL || dlg.m_pdex.dwResultAction == PD_RESULT_APPLY) { - DeleteDC(dlg.m_pdex.hDC); + //User pressed "Cancel", or "Apply" then "Cancel". + if (m_pdex.dwResultAction == PD_RESULT_CANCEL || m_pdex.dwResultAction == PD_RESULT_APPLY) { + DeleteDC(m_pdex.hDC); return; } - - const auto hdcPrinter = dlg.GetPrinterDC(); + const auto hdcPrinter = m_pdex.hDC; if (hdcPrinter == nullptr) { MessageBoxW(L"No printer found."); return; @@ -4050,11 +4173,16 @@ void CHexCtrl::Print() const auto ullTotalPages = (ullTotalLines / iLinesInPage) + 1; int iPagesToPrint { }; - if (dlg.PrintAll()) { + const auto fPrintSelect = m_pdex.Flags & PD_SELECTION; + const auto fPrintRange = m_pdex.Flags & PD_PAGENUMS; + const auto fPrintCurrPage = m_pdex.Flags & PD_CURRENTPAGE; + const auto fPrintAll = !fPrintSelect && !fPrintRange && !fPrintCurrPage; + + if (fPrintAll) { iPagesToPrint = static_cast(ullTotalPages); ullStartLine = 0; } - else if (dlg.PrintRange()) { + else if (fPrintRange) { const auto iFromPage = ppr.nFromPage - 1; const auto iToPage = ppr.nToPage; if (iFromPage <= ullTotalPages) { //Checks for out-of-range pages user input. @@ -4068,7 +4196,7 @@ void CHexCtrl::Print() pDC->SetMapMode(MM_TEXT); pDC->SetViewportOrg(iMarginX, iMarginY); //Move a viewport to have some indent from the edge. - if (dlg.PrintSelection()) { + if (fPrintSelect) { pDC->StartPage(); const auto ullSelStart = m_pSelection->GetSelStart(); const auto ullSelSize = m_pSelection->GetSelSize(); diff --git a/HexCtrl/src/CHexScroll.ixx b/HexCtrl/src/CHexScroll.ixx index 4eaa9f3..ab3de0f 100644 --- a/HexCtrl/src/CHexScroll.ixx +++ b/HexCtrl/src/CHexScroll.ixx @@ -11,7 +11,6 @@ module; #include #include #include -#include export module HEXCTRL.CHexScroll; import HEXCTRL.HexUtility; @@ -89,7 +88,6 @@ namespace HEXCTRL::INTERNAL { auto OnTimer(const MSG& stMsg) -> LRESULT; void RedrawNC()const; void SendParentScrollMsg()const; //Sends the WM_(V/H)SCROLL to the parent window. - static auto WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT; private: static constexpr auto m_iThumbPosMax { 0x7FFFFFFF }; enum class EState : std::uint8_t; @@ -97,8 +95,8 @@ namespace HEXCTRL::INTERNAL { CHexScroll* m_pSibling { }; //Sibling scrollbar, added with AddSibling. HWND m_hWnd { }; //Main window. HWND m_hWndParent { }; //Parent window. - HBITMAP m_bmpArrowFirst { }; //Up or Left arrow bitmap. - HBITMAP m_bmpArrowLast { }; //Down or Right arrow bitmap. + HBITMAP m_hBmpArrowFirst { }; //Up or Left arrow bitmap. + HBITMAP m_hBmpArrowLast { }; //Down or Right arrow bitmap. ULONGLONG m_ullScrollPosCur { }; //Current scroll position. ULONGLONG m_ullScrollPosPrev { }; //Previous scroll position. ULONGLONG m_ullScrollLine { }; //Size of one line scroll, when clicking arrow. @@ -170,7 +168,7 @@ bool CHexScroll::Create(HWND hWndParent, bool fVert, HBITMAP hArrow, ULONGLONG u if (WNDCLASSEXW wc { }; GetClassInfoExW(nullptr, m_pwszScrollClassName, &wc) == FALSE) { wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = CHexScroll::WndProc; + wc.lpfnWndProc = wnd::WndProc; wc.lpszClassName = m_pwszScrollClassName; if (RegisterClassExW(&wc) == 0) { DBG_REPORT(L"RegisterClassExW failed."); @@ -457,18 +455,11 @@ void CHexScroll::OnSetCursor(UINT uHitTest, UINT uMsg) auto CHexScroll::ProcessMsg(const MSG& stMsg)->LRESULT { - static const wnd::MSG_MAP arrMsg[] { - { .uMsg { WM_DESTROY }, .pMsgHandler { &CHexScroll::OnDestroy } }, - { .uMsg { WM_TIMER }, .pMsgHandler { &CHexScroll::OnTimer } } - }; - - for (const auto& ref : arrMsg) { - if (ref.uMsg == stMsg.message) { - return (this->*ref.pMsgHandler)(stMsg); - } + switch (stMsg.message) { + case WM_DESTROY: return CHexScroll::OnDestroy(stMsg); + case WM_TIMER: return CHexScroll::OnTimer(stMsg); + default: return wnd::DefMsgProc(stMsg); } - - return wnd::DefMsgProc(stMsg); } auto CHexScroll::SetScrollPos(ULONGLONG ullNewPos)->ULONGLONG @@ -661,21 +652,21 @@ bool CHexScroll::CreateArrows(HBITMAP hArrow, bool fVert) } }; - m_bmpArrowFirst = ::CreateBitmapIndirect(&stBMP); - m_bmpArrowLast = ::CreateBitmapIndirect(&stBMP); + m_hBmpArrowFirst = ::CreateBitmapIndirect(&stBMP); + m_hBmpArrowLast = ::CreateBitmapIndirect(&stBMP); if (fVert) { - ::SetBitmapBits(m_bmpArrowFirst, dwBytesBmp, pPixelsOrig.get()); //Up arrow. + ::SetBitmapBits(m_hBmpArrowFirst, dwBytesBmp, pPixelsOrig.get()); //Up arrow. lmbFlipVert(pPixelsOrig.get(), dwWidth, dwHeight); //Down arrow. } else { lmbTranspose(pPixelsOrig.get(), dwWidth, dwHeight); lmbFlipVert(pPixelsOrig.get(), dwWidth, dwHeight); - ::SetBitmapBits(m_bmpArrowFirst, dwBytesBmp, pPixelsOrig.get()); //Left arrow. + ::SetBitmapBits(m_hBmpArrowFirst, dwBytesBmp, pPixelsOrig.get()); //Left arrow. lmbFlipHorz(pPixelsOrig.get(), dwWidth, dwHeight); //Right arrow. } - SetBitmapBits(m_bmpArrowLast, dwBytesBmp, pPixelsOrig.get()); + SetBitmapBits(m_hBmpArrowLast, dwBytesBmp, pPixelsOrig.get()); return true; } @@ -739,10 +730,10 @@ void CHexScroll::DrawArrows(HDC hDC)const ::SetBrushOrgEx(hDC, 0, 0, nullptr); const auto hDCSource = CreateCompatibleDC(hDC); - ::SelectObject(hDCSource, m_bmpArrowFirst); //First arrow button. + ::SelectObject(hDCSource, m_hBmpArrowFirst); //First arrow button. ::StretchBlt(hDC, iFirstBtnOffsetDrawX, iFirstBtnOffsetDrawY, iFirstBtnWH, iFirstBtnWH, hDCSource, 0, 0, m_iArrowRCSizePx, m_iArrowRCSizePx, SRCCOPY); - ::SelectObject(hDCSource, m_bmpArrowLast); //Last arrow button. + ::SelectObject(hDCSource, m_hBmpArrowLast); //Last arrow button. ::StretchBlt(hDC, iLastBtnOffsetDrawX, iLastBtnOffsetDrawY, iLastBtnWH, iLastBtnWH, hDCSource, 0, 0, m_iArrowRCSizePx, m_iArrowRCSizePx, SRCCOPY); ::DeleteDC(hDCSource); @@ -1002,10 +993,10 @@ bool CHexScroll::IsSiblingVisible()const auto CHexScroll::OnDestroy(const MSG& stMsg)->LRESULT { - ::DeleteObject(m_bmpArrowFirst); - ::DeleteObject(m_bmpArrowLast); - m_bmpArrowFirst = nullptr; - m_bmpArrowLast = nullptr; + ::DeleteObject(m_hBmpArrowFirst); + ::DeleteObject(m_hBmpArrowLast); + m_hBmpArrowFirst = nullptr; + m_hBmpArrowLast = nullptr; m_hWndParent = nullptr; m_fCreated = false; @@ -1126,27 +1117,4 @@ void CHexScroll::SetThumbPos(int iPos) } SetScrollPos(ullNewScrollPos); -} - -auto CHexScroll::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)->LRESULT -{ - static std::unordered_map uMap; - - //CREATESTRUCTW::lpCreateParams always possesses a `this` pointer, passed to the CreateWindowExW function as lpParam. - //We save it to the static uMap to have access to this->ProcessMsg() method. - if (uMsg == WM_CREATE) { - const auto lpCS = reinterpret_cast(lParam); - uMap[hWnd] = reinterpret_cast(lpCS->lpCreateParams); - return 0; - } - - if (const auto it = uMap.find(hWnd); it != uMap.end()) { - const auto ret = it->second->ProcessMsg({ .hwnd { hWnd }, .message { uMsg }, .wParam { wParam }, .lParam { lParam } }); - if (uMsg == WM_NCDESTROY) { //Remove hWnd from the map on window destruction. - uMap.erase(it); - } - return ret; - } - - return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); } \ No newline at end of file diff --git a/HexCtrl/src/Dialogs/CHexDlgTemplMgr.cpp b/HexCtrl/src/Dialogs/CHexDlgTemplMgr.cpp index 19540ea..77448be 100644 --- a/HexCtrl/src/Dialogs/CHexDlgTemplMgr.cpp +++ b/HexCtrl/src/Dialogs/CHexDlgTemplMgr.cpp @@ -600,7 +600,7 @@ void CHexDlgTemplMgr::OnCheckMin() EndDeferWindowPos(hdwp); EnableDynamicLayoutHelper(true); - m_btnMin.SetBitmap(fMinimize ? m_hBITMAPMax : m_hBITMAPMin); //Set arrow bitmap to the min-max checkbox. + m_btnMin.SetBitmap(fMinimize ? m_hBmpMax : m_hBmpMin); //Set arrow bitmap to the min-max checkbox. } void CHexDlgTemplMgr::OnClose() @@ -662,8 +662,8 @@ void CHexDlgTemplMgr::OnDestroy() m_pAppliedCurr = nullptr; m_pVecFieldsCurr = nullptr; m_hTreeCurrParent = nullptr; - DeleteObject(m_hBITMAPMin); - DeleteObject(m_hBITMAPMax); + DeleteObject(m_hBmpMin); + DeleteObject(m_hBmpMax); m_u64Flags = { }; } @@ -723,26 +723,26 @@ BOOL CHexDlgTemplMgr::OnInitDialog() CRect rcWnd; m_btnMin.GetWindowRect(rcWnd); - m_hBITMAPMin = static_cast(LoadImageW(AfxGetInstanceHandle(), + m_hBmpMin = static_cast(LoadImageW(wnd::GetHinstance(), MAKEINTRESOURCEW(IDB_HEXCTRL_SCROLL_ARROW), IMAGE_BITMAP, rcWnd.Width(), rcWnd.Width(), 0)); - //Flipping m_hBITMAPMin bits vertically and creating m_hBITMAPMax bitmap. + //Flipping m_hBmpMin bits vertically and creating m_hBmpMax bitmap. BITMAP stBMP { }; - GetObjectW(m_hBITMAPMin, sizeof(BITMAP), &stBMP); //stBMP.bmBits is nullptr here. + GetObjectW(m_hBmpMin, sizeof(BITMAP), &stBMP); //stBMP.bmBits is nullptr here. const auto dwWidth = static_cast(stBMP.bmWidth); const auto dwHeight = static_cast(stBMP.bmHeight); const auto dwPixels = dwWidth * dwHeight; const auto dwBytesBmp = stBMP.bmWidthBytes * stBMP.bmHeight; const auto pPixelsOrig = std::make_unique(dwPixels); - GetBitmapBits(m_hBITMAPMin, dwBytesBmp, pPixelsOrig.get()); + GetBitmapBits(m_hBmpMin, dwBytesBmp, pPixelsOrig.get()); for (auto itWidth = 0UL; itWidth < dwWidth; ++itWidth) { //Flip matrix' columns (flip vert). for (auto itHeight = 0UL, itHeightBack = dwHeight - 1; itHeight < itHeightBack; ++itHeight, --itHeightBack) { std::swap(pPixelsOrig[(itHeight * dwHeight) + itWidth], pPixelsOrig[(itHeightBack * dwWidth) + itWidth]); } } - m_hBITMAPMax = CreateBitmapIndirect(&stBMP); - SetBitmapBits(m_hBITMAPMax, dwBytesBmp, pPixelsOrig.get()); - m_btnMin.SetBitmap(m_hBITMAPMin); //Set the min arrow bitmap to the min-max checkbox. + m_hBmpMax = CreateBitmapIndirect(&stBMP); + SetBitmapBits(m_hBmpMax, dwBytesBmp, pPixelsOrig.get()); + m_btnMin.SetBitmap(m_hBmpMin); //Set the min arrow bitmap to the min-max checkbox. return TRUE; } diff --git a/HexCtrl/src/Dialogs/CHexDlgTemplMgr.h b/HexCtrl/src/Dialogs/CHexDlgTemplMgr.h index e3a7720..b3275cb 100644 --- a/HexCtrl/src/Dialogs/CHexDlgTemplMgr.h +++ b/HexCtrl/src/Dialogs/CHexDlgTemplMgr.h @@ -141,8 +141,8 @@ namespace HEXCTRL::INTERNAL { CButton m_btnSwapEndian; //Check-box "Swap endian". CWnd m_wndStaticOffset; //Static text "Template offset:". CWnd m_wndStaticSize; //Static text Template size:". - HBITMAP m_hBITMAPMin { }; //Bitmap for the min checkbox. - HBITMAP m_hBITMAPMax { }; //Bitmap for the max checkbox. + HBITMAP m_hBmpMin { }; //Bitmap for the min checkbox. + HBITMAP m_hBmpMax { }; //Bitmap for the max checkbox. LISTEX::IListExPtr m_pList { LISTEX::CreateListEx() }; CTreeCtrl m_tree; CMenu m_menuTree; //Menu for the tree control. diff --git a/HexCtrl/src/HexUtility.ixx b/HexCtrl/src/HexUtility.ixx index 24a1c70..07d9d2b 100644 --- a/HexCtrl/src/HexUtility.ixx +++ b/HexCtrl/src/HexUtility.ixx @@ -17,6 +17,7 @@ module; #include #include #include +#include export module HEXCTRL.HexUtility; export import StrToNum; @@ -408,17 +409,63 @@ export namespace HEXCTRL::INTERNAL { } namespace wnd { //Windows GUI related stuff. - template - struct MSG_MAP { - using MsgHandler = LRESULT(T::*)(const MSG&); //Function that takes ref to the standard Windows MSG struct. - UINT uMsg { }; - MsgHandler pMsgHandler { }; - }; + [[nodiscard]] auto GetHinstance() -> HINSTANCE { + return AfxGetInstanceHandle(); + } - [[nodiscard]] auto DefMsgProc(const MSG& stMsg) -> LRESULT { + auto DefMsgProc(const MSG& stMsg) -> LRESULT { return ::DefWindowProcW(stMsg.hwnd, stMsg.message, stMsg.wParam, stMsg.lParam); } + template + auto CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT + { + static std::unordered_map uMap; + + //CREATESTRUCTW::lpCreateParams always possesses a `this` pointer, passed to the CreateWindowExW function as lpParam. + //We save it to the static uMap to have access to this->ProcessMsg() method. + if (uMsg == WM_CREATE) { + const auto lpCS = reinterpret_cast(lParam); + uMap[hWnd] = reinterpret_cast(lpCS->lpCreateParams); + return 0; + } + + if (const auto it = uMap.find(hWnd); it != uMap.end()) { + const auto ret = it->second->ProcessMsg({ .hwnd { hWnd }, .message { uMsg }, .wParam { wParam }, .lParam { lParam } }); + if (uMsg == WM_NCDESTROY) { //Remove hWnd from the map on window destruction. + uMap.erase(it); + } + return ret; + } + + return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + template + auto CALLBACK DlgWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> INT_PTR { + //DlgWndProc should return zero for all non-processed messages. + //In that case messages will be processed by Windows default dialog proc. + //Non-processed messages should not be passed to DefWindowProcW or DefDlgProcW. + //Processed messages should return any non-zero value, depending on message type. + + static T* m_pThis { }; + + //DialogBoxParamW and CreateDialogParamW dwInitParam arg is sent with WM_INITDIALOG as lParam. + if (uMsg == WM_INITDIALOG) { + m_pThis = reinterpret_cast(lParam); + } + + if (m_pThis != nullptr) { + const auto ret = m_pThis->ProcessMsg({ .hwnd { hWnd }, .message { uMsg }, .wParam { wParam }, .lParam { lParam } }); + if (uMsg == WM_NCDESTROY) { + m_pThis = nullptr; + } + return ret; + } + + return 0; + } + void FillSolidRect(HDC hDC, LPCRECT pRC, COLORREF clr) { //Replicates CDC::FillSolidRect. ::SetBkColor(hDC, clr);