catalogue
3. Detect whether the current application exists
II Button activate ButtonActive
V Simulate mouse button message MouseKeboardClick
VII SCreenShot function SCreenShot
VIII ToolTips control prompt box
IX Translucent profiled window TransparentCtrl
2. Translucent profiled window
3. Translucent profiled window with control display
4. Fixed translucent special-shaped window
I Enum window EnumDialog
1. Enumeration mode
(1) method 1: GetWindow
HWND hChildWnd = ::GetWindow(GetDesktopWindow()->GetSafeHwnd(), GW_CHILD); while (hChildWnd) { //Do something hChildWnd = ::GetWindow(hChildWnd, GW_HWNDNEXT); }
(2) mode 2: EnumWindows/EnumChildWindows
EnumWindows(EnumWindowsPro, (LPARAM)this);//Enumerate all current windows ... ... BOOL CALLBACK EnumWindowsPro(HWND hWnd, LPARAM lParam) { //Do something return TRUE; }
2. Find window
(1) FindWindow
HWND hWnd = ::FindWindow(NULL, _T("Calculator"));//Class name, window title
(2) FindWindowEx
//Parent window handle, child window handle, window class name, window title HWND hInputWnd = ::FindWindowEx(hWnd, NULL, _T("Window"), NULL);
3. Detect whether the current application exists
(1) there are several methods to detect the existence of the current application, which are not described one by one here. Only one is introduced here, which meets the following functions: when it is detected that the application already exists, the program will pop up directly and put it on the top.
TCHAR g_acProName[] = _T("{E91C1C60-DC70-460D-9299-FC67422ECA23}"); HANDLE g_hValue = (HANDLE)9527; ... ... void CEnumDialogDlg::CheckProExist() { HWND hWnd = nullptr; EnumWindows(EnumExistPro, (LPARAM)&hWnd); if (nullptr != hWnd)//The description window exists { AfxMessageBox(_T("A program is already running...")); ::ShowWindow(hWnd, SW_NORMAL); ::SetForegroundWindow(hWnd); ExitProcess(0); return; } ::SetProp(m_hWnd, g_acProName, g_hValue);//set a property } ... ... BOOL CALLBACK EnumExistPro(HWND hWnd, LPARAM lParam) { HANDLE hValue = ::GetProp(hWnd, g_acProName); if (g_hValue == hValue)//Get value { *(HWND*)lParam = hWnd;//Pass window handle out return FALSE; } return TRUE; }
II Button activate ButtonActive
1. principle
We know that all controls in MFC are essentially window classes, so we can traverse all windows of the current program and activate the inactive windows. This example is only useful for programs developed by MFC. The reason is that many UI s are developed with DirectUI. We know that this interface essentially has only one window and controls are painted.
2. realization
EnumChildWindows(hWnd, EnumWindowsPro, NULL); ... ... BOOL CALLBACK EnumWindowsPro(HWND hWnd, LPARAM lParam) { if (FALSE == IsWindowEnabled(hWnd)) { EnableWindow(hWnd, TRUE); } return TRUE; }
III Star viewer AsterPassword
1. Principle
The Edit class developed by MFC encapsulates the win32 native control Edit, and we know that the way for the native control to obtain the Edit text is SendMessage(hWnd, WM_GETTEXT, lrTextLen + 1, (LPARAM)pcBuf). Then we can obtain the password as long as we use WindowFromPoint to find the star Edit window.
The interface imitates spy + +. If you try QQ,YY will find that it has no effect at all (don't do bad things). The reason is that QQ uses its own DirectUI library and yy uses qt. If you are familiar with their interface library, you can also write the corresponding viewer.
2. realization
HWND hWndParent = ::WindowFromPoint(pt);//Gets the handle of the window where the current point is located CRect stRect = { 0 }; HWND hWndCurrent = ::GetWindow(hWndParent, GW_CHILD);//Gets the child window of the parent window while (NULL != hWndCurrent) { ::GetWindowRect(hWndCurrent, &stRect);//Gets the size of the current window if (::PtInRect(stRect, pt))//Detect whether the mouse position is within the current window break; else hWndCurrent = ::GetWindow(hWndCurrent, GW_HWNDNEXT);//Gets the next sibling window of the current window } ... ... LRESULT lrTextLen = ::SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0);//Get Edit text length
IV Image Explorer
1. principle
Use ListCtrl to obtain the picture information of the folder, and then use PicCtrl to display each item in ListCtrl. gif format pictures are drawn by gdi +.
2. realization
(1) normal picture drawing: directly draw with CImage
CImage objImage; HRESULT hr = objImage.Load(lpFilePath); if (SUCCEEDED(hr)) { CRect stPicRect = { 0 }; GetDlgItem(IDC_STC_SHOW)->GetClientRect(stPicRect);//Gets the size of the picControl //Set picture coordinates CRect stImagePos = { 0 }; AdjustImageRect(stImagePos, stPicRect, objImage.GetWidth(), objImage.GetHeight()); //Start drawing CDC* pDC = CDC::FromHandle(::GetDC(GetDlgItem(IDC_STC_SHOW)->m_hWnd)); pDC->FillRect(stPicRect, CBrush::FromHandle(::CreateSolidBrush(GetSysColor(COLOR_3DFACE))));//Background fill SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);//Before calling strechblt, you need to set the device context to stretch mode objImage.StretchBlt(pDC->m_hDC, stImagePos.left, stImagePos.top, stImagePos.right - stImagePos.left, stImagePos.bottom - stImagePos.top, SRCCOPY);//Can stretch ::ReleaseDC(GetDlgItem(IDC_STC_SHOW)->m_hWnd, pDC->m_hDC); }
(2) gif format picture drawing
void CImageExploreDlg::DrawGif(LPCTSTR lpFilePath) { if (nullptr == lpFilePath) return; m_pGifImage = Gdiplus::Image::FromFile(lpFilePath);//Load picture if (nullptr != m_pGifImage) { //Gets the size of the picControl CRect stPicRect = { 0 }; GetDlgItem(IDC_STC_SHOW)->GetClientRect(stPicRect); //Set picture coordinates CRect stImagePos; AdjustImageRect(stImagePos, stPicRect, m_pGifImage->GetWidth(), m_pGifImage->GetHeight()); //coordinate transformation m_stGifPos.X = (Gdiplus::REAL)stImagePos.left; m_stGifPos.Y = (Gdiplus::REAL)stImagePos.top; m_stGifPos.Width = (Gdiplus::REAL)stImagePos.Width(); m_stGifPos.Height = (Gdiplus::REAL)stImagePos.Height(); //draw m_uiCurFrame = 0; SetTimer(1, 100, NULL); } } ... ... void CImageExploreDlg::OnTimer(UINT_PTR nIDEvent) { PlayGif(); CDialogEx::OnTimer(nIDEvent); } ... ... void CImageExploreDlg::PlayGif() { //Get PIC CONTROL size CRect stPicRect = { 0 }; GetDlgItem(IDC_STC_SHOW)->GetClientRect(stPicRect); //Get gif information GUID acGuidBuf[MAX_PATH] = { 0 }; UINT uiCount = m_pGifImage->GetFrameDimensionsCount();//The dimension of the frame of the GIF file m_pGifImage->GetFrameDimensionsList(acGuidBuf, uiCount);// Gets the GUID of the image frame UINT uiFrameSize = m_pGifImage->GetFrameCount(&acGuidBuf[0]);//Total number of motion pictures //draw CDC* pDC = CDC::FromHandle(::GetDC(GetDlgItem(IDC_STC_SHOW)->m_hWnd)); Gdiplus::Graphics graphics(pDC->GetSafeHdc()); if (0 == m_uiCurFrame) pDC->FillRect(stPicRect, CBrush::FromHandle(::CreateSolidBrush(GetSysColor(COLOR_3DFACE))));//Background fill graphics.DrawImage(m_pGifImage, m_stGifPos, 0, 0, (Gdiplus::REAL)m_pGifImage->GetWidth(), (Gdiplus::REAL)m_pGifImage->GetHeight(), Gdiplus::UnitPixel); //Set gif next frame GUID pageGuid = Gdiplus::FrameDimensionTime; m_uiCurFrame = (++m_uiCurFrame) % uiFrameSize; m_pGifImage->SelectActiveFrame(&pageGuid, m_uiCurFrame);//Get next frame ::ReleaseDC(GetDlgItem(IDC_STC_SHOW)->m_hWnd, pDC->m_hDC); }
V Simulate mouse button message MouseKeboardClick
1. principle
(1) Description: query MSDN, keybd_event and mouse_event is not recommended. Instead, SendInput is used to simulate the key and mouse messages.
(2) keyboard message: simulate the hotkey "Ctrl + Alt + P" of "Netease cloud music" to realize the "play / pause" function. First use
Spy + + obtains the window class name of "Netease cloud", then judges whether the program is open, and sends a keyboard message through SendInput
Drag and drop / pause function
(3) mouse message: when the mouse clicks a button, the mouse will appear on another button and click automatically to realize the click response message of another button.
2. realization
(1) simulation of keyboard message: it should be explained here that if your computer is equipped with 360, you need to add the program to
360's trust zone. Otherwise, 360 will intercept the SendPut message, and the demo program will not see the effect.
void CMouseKeyboardClickDlg::OnBnClickedBtnHotkey() { HWND hWnd = ::FindWindow(_T("OrpheusBrowserHost"), NULL);//Find the window class of Netease cloud music with spy + + if (!hWnd) { AfxMessageBox(_T("No Netease cloud music program found")); return; } INPUT astKey[6] = { 0 }; astKey[0].type = astKey[1].type = astKey[2].type = astKey[3].type = astKey[4].type = astKey[5].type = INPUT_KEYBOARD; //Control + Alt + P hotkey: play / pause astKey[0].ki.wVk = astKey[5].ki.wVk = VK_CONTROL; astKey[1].ki.wVk = astKey[4].ki.wVk = VK_MENU; astKey[2].ki.wVk = astKey[3].ki.wVk = 'P'; astKey[3].ki.dwFlags = astKey[4].ki.dwFlags = astKey[5].ki.dwFlags = KEYEVENTF_KEYUP; //Use system timestamp astKey[0].ki.time = astKey[1].ki.time = astKey[2].ki.time = GetTickCount(); Sleep(100); astKey[3].ki.time = astKey[4].ki.time = astKey[5].ki.time = GetTickCount(); SendInput(ARRAYSIZE(astKey), astKey, sizeof(INPUT)); }
(2) simulation of mouse message
void CMouseKeyboardClickDlg::OnBnClickedBtnMouse() { //Simple test: if external is used exe. You can use spy + + and:: FindWindow to get the window handle INPUT astKey[2] = { 0 }; astKey[0].type = astKey[1].type = INPUT_MOUSE; astKey[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; astKey[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; //Reset mouse position CRect stRect = { 0 }; ::GetWindowRect(GetDlgItem(IDC_BTN_TESTOBJ)->m_hWnd, &stRect); ::SetCursorPos(stRect.left + (stRect.right - stRect.left) / 2, stRect.top + (stRect.bottom - stRect.top) / 2); SendInput(ARRAYSIZE(astKey), astKey, sizeof(INPUT)); } ... ... void CMouseKeyboardClickDlg::OnBnClickedBtnTestobj() { // TODO: add control notification handler code here AfxMessageBox(_T("The test button is clicked")); }
Vi Screen magnifier
1. principle
The StretchBlt function is mainly used to scale the bitmap.
2. realization
void CScreenMagnifyDlg::StretchScreenToBitmap(CRect stShowRect, UINT uiZoom, CBitmap& bitmapShow) { if (nullptr != bitmapShow.m_hObject) bitmapShow.DeleteObject();//If the bitmap exists, the resource is deleted and will be created later to avoid disclosure CDC* pDC = CDC::FromHandle(::GetDC(NULL)); int iScreenX = GetSystemMetrics(SM_CXSCREEN); int iScreenY = GetSystemMetrics(SM_CYSCREEN); //=============Gets the bitmap of the entire screen CDC screenDC; CBitmap bitmapScreen; screenDC.CreateCompatibleDC(pDC); bitmapScreen.CreateCompatibleBitmap(pDC, iScreenX, iScreenY); CBitmap* pOldScreen = screenDC.SelectObject(&bitmapScreen); screenDC.BitBlt(0, 0, iScreenX, iScreenY, pDC, 0, 0, SRCCOPY); //=============Gets the bitmap of the enlarged screen area CDC memDC; CRect stRect = { 0 }; // int iWidth = stShowRect.Width() / uiZoom; int iHeight = stShowRect.Height() / uiZoom; //Get the enlarged screen coordinates AdjustRect(iScreenX, iScreenY, iWidth, iHeight, stRect); //Get bitmap memDC.CreateCompatibleDC(pDC); bitmapShow.CreateCompatibleBitmap(pDC, stShowRect.Width(), stShowRect.Height()); CBitmap* pOldMem = memDC.SelectObject(&bitmapShow); SetStretchBltMode(memDC.m_hDC, COLORONCOLOR);//Set the device context to stretch mode memDC.StretchBlt(0, 0, stShowRect.Width(), stShowRect.Height(), &screenDC, stRect.left, stRect.top, iWidth, iHeight, SRCCOPY); //Release resources screenDC.SelectObject(pOldScreen); memDC.SelectObject(pOldMem); bitmapScreen.DeleteObject(); ::ReleaseDC(NULL, pDC->m_hDC); }
VII SCreenShot function SCreenShot
1. principle
Let's just talk about the principle of "custom screenshot". Create a full screen modal dialog box, copy the current screen bitmap to the dialog box, and obtain the areas that need screenshots in combination with the crittracker rubber band class, instead of the areas that do not need screenshots
gdi + draw a gray mask, so you can achieve the effect of QQ screenshot. Of course, only the core part is processed here. To achieve a complete effect, you only need to use WindowFromPoint to obtain the window area, and then add a Tooltip at the lower right of the screenshot. To realize its function is a complete QQ screenshot.
2. realization
void CCaptureDlg::DrawFrame() { CDC* pDC = GetDC(); //CDC::FromHandle(::GetDC(NULL)); //Double buffering to avoid flicker CDC BufferDC; CBitmap bitBuffer; BufferDC.CreateCompatibleDC(pDC); bitBuffer.CreateCompatibleBitmap(pDC, m_iScreenX, m_iScreenY); CBitmap* pOldBitBuffer = BufferDC.SelectObject(&bitBuffer); CDC memDC; memDC.CreateCompatibleDC(&BufferDC); CBitmap* pOldBitMem = memDC.SelectObject(&m_ScreenBit); BufferDC.BitBlt(0, 0, m_iScreenX, m_iScreenY, &memDC, 0, 0, SRCCOPY);//Copy bitmap on memory DC to window DC if ((0 == m_rect.Width()) && (0 == m_rect.Height())) { m_objGdiplusDraw.DrawImage(&BufferDC, 0, 0, m_iScreenX, m_iScreenY, 0, 0, 8, 8 );//Mask the picture } else//Redraw while dragging the mouse { AdjustRect(m_rect);//Prevent dragging the rectangular box out of bounds. When the coordinates are negative, readjust the coordinates CRect stRect = m_rect; stRect.NormalizeRect();//Adjust rectangular coordinates; eg, press and hold the mouse to drag down, and the coordinates are normal; What if you hold down the mouse and drag it up? This function inverts the coordinates CRectTracker::Draw(&BufferDC);//Draw a rectangle m_objGdiplusDraw.DrawImage(&BufferDC, 0, 0, m_iScreenX, stRect.top, 0, 0, 8, 8);//Upper region m_objGdiplusDraw.DrawImage(&BufferDC, 0, stRect.top, stRect.left, stRect.Height(), 0, 0, 8, 8);//Left region m_objGdiplusDraw.DrawImage(&BufferDC, stRect.right, stRect.top, m_iScreenX - stRect.right, stRect.Height(), 0, 0, 8, 8);//Right area m_objGdiplusDraw.DrawImage(&BufferDC, 0, stRect.bottom, m_iScreenX, m_iScreenY - stRect.bottom, 0, 0, 8, 8);//Lower area } pDC->BitBlt(0, 0, m_iScreenX, m_iScreenY, &BufferDC, 0, 0, SRCCOPY);//Paste the contents of the memory DC on the screen DC at one time memDC.SelectObject(pOldBitMem); BufferDC.SelectObject(pOldBitBuffer); ReleaseDC(pDC); }
VIII ToolTips control prompt box
1. principle
MFC encapsulates a ctooltiptctrl class for us, which is specially used to provide "prompt box window" for controls and windows
2. realization
(1) static addition: when the content of the window changes, the content of the prompt box remains unchanged.
CString strDirPath = _T("C:\\Program Files (x86)\\Tencent\\WeMeet\\2.8.8.403\\resource\\Default\\html"); //Static addition if (!m_objToolTip.Create(this, TTS_ALWAYSTIP)) return FALSE; ::SetWindowTheme(m_objToolTip.m_hWnd, _T(""), _T(""));//Compatible with different visual style information sets to solve the failure of SetTipTextColor SetDlgItemText(IDC_EDIT_STATIC, strDirPath); m_objToolTip.SetTipTextColor(RGB(99, 184, 255)); m_objToolTip.AddTool(GetDlgItem(IDC_EDIT_STATIC), strDirPath); m_objToolTip.Activate(TRUE); ... ... BOOL CToolTipsDlg::PreTranslateMessage(MSG* pMsg) { if (NULL != m_objToolTip.m_hWnd) m_objToolTip.RelayEvent(pMsg);//Transfer the mouse message to the prompt tool class for processing return CDialogEx::PreTranslateMessage(pMsg); }
(2) dynamic addition: when the content of the window changes, the content of the prompt box changes.
if (!m_objToolTipAuto.Create(this)) return FALSE; SetDlgItemText(IDC_EDIT_AUTO, strDirPath); EnableToolTips(TRUE);//Main window allow prompt ... ... ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &CToolTipsDlg::OnTtnNeedText) ... ... BOOL CToolTipsDlg::OnTtnNeedText(UINT id, NMHDR *pNMHDR, LRESULT *pResult)//Example given by msdn { UNREFERENCED_PARAMETER(id);//No treatment TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR; UINT_PTR nID = pNMHDR->idFrom; //Get the target window ID, which may be HWND BOOL bRet = FALSE; if (pTTT->uFlags & TTF_IDISHWND) { //Indicates whether nID is HWND bRet = TRUE; // idFrom is actually the HWND of the tool nID = ::GetDlgCtrlID((HWND)nID); //Get the ID value from HWND. Of course, you can also judge by HWND value switch (nID) { case IDC_EDIT_AUTO: m_strText.Empty(); GetDlgItemText(nID, m_strText); pTTT->lpszText = (LPTSTR)(LPCTSTR)m_strText; pTTT->hinst = AfxGetResourceHandle(); default:break; } } *pResult = 0; return bRet; }
IX Translucent profiled window TransparentCtrl
1. Text profile window
(1) clipping region: if a window is placed in the clipping region, the part of the window that is not in the region will be clipped. Moreover, MFC also helps us encapsulate the CRgn class, which is very simple. For details, please refer to:
https://blog.csdn.net/qwdpoiguw/article/details/72898473
(2) path: the path is also a GDI object. Unlike brushes and brushes, MFC does not help us encapsulate the path, so we need to call the CDC API function for operation, and only a specific path function is useful when drawing the path, starting with beginPath and ending with endPath. The introduction of path mainly enriches the text display function. For details, please refer to
https://blog.csdn.net/love_xsq/article/details/53635163
(3) principle: first use the path to draw the font, then convert the path into an area, and finally put the window into the area, so that the special-shaped text window is formed.
(4) realization
void CFontDlg::DrawFont() { CRect stRect; GetWindowRect(&stRect); CDC* pDC = CDC::FromHandle(::GetDC(GetSafeHwnd())); //Create font CFont ojbFont; ojbFont.CreateFont( 100, 40, 0, 0, FW_HEAVY, TRUE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Song typeface")); //transparent pDC->SetBkMode(TRANSPARENT); CFont *pOldFont = pDC->SelectObject(&ojbFont); //Path drawing pDC->BeginPath(); pDC->TextOut(0, 0, _T("I like watching the sunrise")); pDC->EndPath(); pDC->SelectObject(pOldFont); //Convert path to region HRGN wndRgn = ::PathToRegion(pDC->m_hDC); SetWindowRgn(wndRgn, TRUE); ::ReleaseDC(GetSafeHwnd(), pDC->m_hDC); }
2. Translucent profiled window
(1) precondition: ModifyStyleEx(0, WS_EX_LAYERED); Windows must be hierarchical
(2) function description: SetLayeredWindowAttributes sets the transparency of the entire window;
UpdateLayeredWindow can cut out the transparent area of the bitmap on the basis of setting the transparency of the window
(3) realization
void CTransDlg::DrawTransDlg() { ModifyStyleEx(0, WS_EX_LAYERED);//Set layered window //Get window size CRect stWindRect = { 0 }; GetWindowRect(&stWindRect); //Get picture resources //Image* pImage = Image::FromFile(_T(".\\res\\background.png")); Image * pImage = CUtility::LoadImage(IDB_PNG2, _T("PNG"), AfxGetResourceHandle()); if (nullptr == pImage) return; //Get picture size int iWidth = pImage->GetWidth(); int iHeight = pImage->GetHeight(); //Modify window size MoveWindow(stWindRect.left, stWindRect.top, iWidth, iHeight); //mapping CDC* pDC = CDC::FromHandle(::GetDC(GetSafeHwnd())); //Memory DC select bitmap CDC memDC; CBitmap bmpMem; memDC.CreateCompatibleDC(pDC); bmpMem.CreateCompatibleBitmap(pDC, iWidth, iHeight); CBitmap* pOldMem = memDC.SelectObject(&bmpMem); //gdi + draw pictures Graphics graphics(memDC);//Draw on memory DC graphics.DrawImage(pImage, 0, 0, iWidth, iHeight); //Update window parameter settings POINT ptWinPos = { stWindRect.left, stWindRect.top }; POINT ptSrc = { 0, 0 }; SIZE sizeWindow = { iWidth, iHeight }; BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.AlphaFormat = AC_SRC_ALPHA; bf.SourceConstantAlpha = 254; //update windows UpdateLayeredWindow(pDC, &ptWinPos, &sizeWindow, &memDC, &ptSrc, 0, &bf, ULW_ALPHA); //Release resources memDC.SelectObject(pOldMem); DeleteObject(bmpMem); ::ReleaseDC(GetSafeHwnd(), pDC->m_hDC); }
(4) question: there is a translucent special-shaped form, but the button control I put on the window is missing. What's going on? Look at the window drawing section. gdi + only draws translucent pictures, and then updates the window. Of course, you can only see translucent bitmaps. How do I see the buttons I drag and drop on the window?
3. Translucent profiled window with control display
(1) continue the above problem: if we want to see the control we drag and drop, we can only draw the control on the bitmap before updating the window, so that we can see it! OK, according to this idea, we need to draw all the controls on the window before updating the window! I happen to see an example like this: https://www.codeproject.com/Articles/34158/Cool-Semi-transparent-and-Shaped-Dialogs-with-Stan.
(2) principle: use two windows, one original window A and one display window B. Create A window B of the same size as window A, paste window B on window A, and set window A to be fully transparent. Then through SendMessage: WM_PRINT takes A snapshot of all controls on window A and draws it on the bitmap of window B.
In this way, the original window A is used to process controls and window messages, and window B is used to display to the user. The reason why the user can see the behavior change of the fake control (eg, clicking the button will change) is that all the controls on the original window A are subclassed, and the control snapshot is refreshed to window B for display.
(3) realization
void CImgDialogBase::Refresh(void) { if( m_bIsRefreshing ) return; if( !IsWindow(m_hFakeWnd) ) return; m_bIsRefreshing = TRUE; RECT rc; ::GetWindowRect( m_hFakeWnd, &rc); POINT ptSrc = { 0, 0}; POINT ptWinPos = { rc.left, rc.top}; SIZE szWin = { m_nWidth, m_nHeigh }; BLENDFUNCTION stBlend = { AC_SRC_OVER, 0, m_nAlpha, AC_SRC_ALPHA }; HDC hDC = ::GetDC(m_hFakeWnd); HDC hdcMemory = ::CreateCompatibleDC(hDC); BITMAPINFOHEADER stBmpInfoHeader = { 0 }; int nBytesPerLine = ((m_nWidth * 32 + 31) & (~31)) >> 3; stBmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); stBmpInfoHeader.biWidth = m_nWidth; stBmpInfoHeader.biHeight = m_nHeigh; stBmpInfoHeader.biPlanes = 1; stBmpInfoHeader.biBitCount = 32; stBmpInfoHeader.biCompression = BI_RGB; stBmpInfoHeader.biClrUsed = 0; stBmpInfoHeader.biSizeImage = nBytesPerLine * m_nHeigh; PVOID pvBits = NULL; HBITMAP hbmpMem = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader, DIB_RGB_COLORS, &pvBits, NULL, 0); ASSERT(hbmpMem != NULL); memset( pvBits, 0, m_nWidth * 4 * m_nHeigh); if(hbmpMem) { HGDIOBJ hbmpOld = ::SelectObject( hdcMemory, hbmpMem); Graphics graph(hdcMemory); graph.SetSmoothingMode(SmoothingModeNone); // Draw the background graph.DrawImage( m_pImage, 0, 0, m_nWidth, m_nHeigh); // On draw OnDraw(graph); // Draw all the controls HWND hwndChild = ::GetWindow( GetSafeHwnd(), GW_CHILD); while(hwndChild) { DrawCtrl( graph, hDC, hwndChild); hwndChild = ::GetWindow( hwndChild, GW_HWNDNEXT); } // draw the caret DrawCaret(graph); ::UpdateLayeredWindow( m_hFakeWnd , hDC , &ptWinPos , &szWin , hdcMemory , &ptSrc , 0 , &stBlend , ULW_ALPHA ); graph.ReleaseHDC(hdcMemory); ::SelectObject( hdcMemory, hbmpOld); ::DeleteObject(hbmpMem); } ::DeleteDC(hdcMemory); ::DeleteDC(hDC); m_bIsRefreshing = FALSE; }
(4) problem: there are also problems here, such as Edit has no cursor, Slider has no Slider, listCtrl scroll bar background is black, etc. the program specially adds a cursor for Edit. What should I do if the cursor position changes? Obviously, this design is also unreasonable. Users need to set a new shape state for controls that do not meet the requirements. What should I do?
4. Fixed translucent special-shaped window
(1) continue the above question: is it possible to place the control of the original window A on the bitmap of window B and empty it, so that we can see the control of the original window. We will expand further according to this idea.
(2) principle: still use two windows, original window A and special-shaped window B. Cut out all the controls on window A, find their union C, and then find the complement between windows B and C. in this way, the control area of window A is buckled out on window B.
(3) realization
void CMyDrawBase::OnDraw() { if (!IsWindow(m_hFakeWnd)) return; //Get window size CRect stWindRect = { 0 }; ::GetWindowRect(m_hFakeWnd, &stWindRect); //mapping CDC* pDC = CDC::FromHandle(::GetDC(m_hFakeWnd)); //Memory DC select bitmap CDC memDC; CBitmap bmpMem; memDC.CreateCompatibleDC(pDC); bmpMem.CreateCompatibleBitmap(pDC, m_nWidth, m_nHeight); CBitmap* pOldMem = memDC.SelectObject(&bmpMem); //gdi + draw pictures Graphics graphics(memDC);//Draw on memory DC graphics.DrawImage(m_pImage, 0, 0, m_nWidth, m_nHeight); //Clipping Region CRgn objRgnCtrl, objRgnTemp, objRgnFakeWnd; GetCtrlRgn(objRgnCtrl, objRgnTemp);//Gets the region union of all controls objRgnFakeWnd.CreateRectRgn(0, 0, m_nWidth, m_nHeight);//Get fakewnd area objRgnFakeWnd.CombineRgn(&objRgnFakeWnd, &objRgnCtrl, RGN_DIFF);//Remove the area of the control pDC->SelectObject(&objRgnFakeWnd); //Update window parameter settings POINT ptWinPos = { stWindRect.left, stWindRect.top }; POINT ptSrc = { 0, 0 }; SIZE sizeWindow = { m_nWidth, m_nHeight }; BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.AlphaFormat = AC_SRC_ALPHA; bf.SourceConstantAlpha = m_iAlpha; //update windows ::UpdateLayeredWindow(m_hFakeWnd, pDC->m_hDC, &ptWinPos, &sizeWindow, memDC.m_hDC, &ptSrc, 0, &bf, ULW_ALPHA); //Place window in Crop Region ::SetWindowRgn(m_hWnd, objRgnCtrl, TRUE); ::SetWindowRgn(m_hFakeWnd, objRgnFakeWnd, TRUE); //Release resources memDC.SelectObject(pOldMem); DeleteObject(bmpMem); objRgnCtrl.DeleteObject(); objRgnTemp.DeleteObject(); objRgnFakeWnd.DeleteObject(); ::ReleaseDC(m_hFakeWnd, pDC->m_hDC); } void CMyDrawBase::GetCtrlRgn(CRgn& rgnDst, CRgn& rgnSrc) { CRect stRect; HWND hwndChild = ::GetWindow(m_hWnd, GW_CHILD);//Traverse all controls under the main window //Gets the region of the first control ::GetWindowRect(hwndChild, &stRect); ScreenToClient(&stRect); rgnDst.CreateRectRgnIndirect(stRect); while (hwndChild) { hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT); if (!IsWindow(hwndChild)) break; //Get the nth control area ::GetWindowRect(hwndChild, &stRect); ScreenToClient(&stRect); rgnSrc.CreateRectRgnIndirect(stRect); rgnDst.CombineRgn(&rgnDst, &rgnSrc, RGN_OR);//Find the union of two regions rgnSrc.DeleteObject();//Be sure to delete it, or there will be a memory leak } }
(4) renderings
X Tray button TrayTip
1. Adaptive window change
(1) principle: record the position of the original window and all controls. When the window size changes, calculate the window scaling in OnSize, and then resize the controls through the scaling.
(2) realization
int CTrayTilDlg::CalSize(float fSize)//Fix control coordinate values { int iTemp = (int)fSize; float fTemp = fSize - (float)iTemp; if (0 >= fSize) return iTemp + (int)((fTemp > -m_fReferSize) ? 0 : -1.0);// else return iTemp + (int)((fTemp < m_fReferSize) ? 0 : 1.0);// } void CTrayTilDlg::ReSize(UINT uiType, int iX, int iY) { if ((0 == m_stOldRect.Width()) || (0 == m_stOldRect.Height())) return; float fZoomX = (float)(iX - m_stOldRect.Width()) / (float)m_stOldRect.Width(); float fZoomY = (float)(iY - m_stOldRect.Height()) / (float)m_stOldRect.Height(); HWND hChildWnd = ::GetWindow(GetSafeHwnd(), GW_CHILD); while (hChildWnd) { CRect stRect = m_mapCtrl.at(::GetDlgCtrlID(hChildWnd));//use. at will detect the serial number value and report an error, [] will not int iLeft = stRect.left + CalSize(stRect.left * fZoomX); int iTop = stRect.top + CalSize(stRect.top * fZoomY); int iWidth = stRect.Width() + CalSize(stRect.Width() * fZoomX); int iHeight = stRect.Height() + CalSize(stRect.Height() * fZoomY); ::MoveWindow(hChildWnd, iLeft, iTop, iWidth, iHeight, FALSE);//Reset control position hChildWnd = ::GetWindow(hChildWnd, GW_HWNDNEXT); } Invalidate(TRUE);//Redraw the entire window }
2. Tray icon
(1) principle: while creating the tray icon, use the timer to replace the bitmap of the tray icon to achieve the effect of QQ flashing, and use WM_TRAY_MSG message response to achieve the effect of double clicking the pop-up window and right clicking the pop-up menu.
(2) realization
void CTrayTilDlg::MyTrayIcon(DWORD dwMessage, DWORD dwIconIDd, LPCTSTR lpTipTitle) { NOTIFYICONDATA stNotifyIcon = { 0 }; stNotifyIcon.cbSize = sizeof (NOTIFYICONDATA); stNotifyIcon.hWnd = GetSafeHwnd(); stNotifyIcon.uID = IDR_MAINFRAME;//Note that after ADD, this value is used as a unique identifier, whether Delete or Modify stNotifyIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;//NIF_INFO bubble prompt stNotifyIcon.uCallbackMessage = WM_TRAY_MSG;//Set the response message of the callback function stNotifyIcon.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(dwIconIDd));//Get bitmap if (nullptr != lpTipTitle) { _tcscpy_s(stNotifyIcon.szTip, ARRAYSIZE(stNotifyIcon.szTip), lpTipTitle); } _tcscpy_s(stNotifyIcon.szInfo, ARRAYSIZE(stNotifyIcon.szInfo), _T("This is a bubble tip")); _tcscpy_s(stNotifyIcon.szInfoTitle, ARRAYSIZE(stNotifyIcon.szInfoTitle), _T("Bubble tip title")); Shell_NotifyIcon(dwMessage, &stNotifyIcon); } ... ... void CTrayTilDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: add message handler code here and / or call default values static BOOL bTrayIcon = TRUE; bTrayIcon = !bTrayIcon; DWORD dwIconID = (TRUE == bTrayIcon) ? IDI_ICON1 : IDR_MAINFRAME; MyTrayIcon(NIM_MODIFY, dwIconID, NULL); CDialogEx::OnTimer(nIDEvent); } ... ... LRESULT CTrayTilDlg::OnTrayIcon(WPARAM wParam, LPARAM lParam) { UINT uiMessage = (UINT)lParam; switch (uiMessage) { case WM_RBUTTONUP://Pop-up Menu { CMenu objMenu, *pobjMenu; objMenu.LoadMenu(IDR_MENU_TRAY); pobjMenu = objMenu.GetSubMenu(0); CPoint stPoint; GetCursorPos(&stPoint); pobjMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, stPoint.x, stPoint.y, this); } break; case WM_LBUTTONDBLCLK://Double click the popup { KillTimer(1); ShowWindow(SW_SHOW);//Normal display window MyTrayIcon(NIM_MODIFY, IDR_MAINFRAME, NULL);//Prevent tray icons from appearing transparent } break; default: break; } return TRUE; }
Xi summary
1. These examples are based on the tutorial of syc of VC post station. Some examples have been extended to be familiar with MFC programming
2. Download address: https://download.csdn.net/download/zhoumin4576/20030100