www.gusucode.com > VC++实现Vista玻璃窗体程序 > VC++实现Vista玻璃窗体程序/gusucode/Vista玻璃窗体程序文件/Src/ImgDialogBase.cpp
// ImgDialogBase.cpp : implementation file // #include "stdafx.h" #include "ImgDialogBase.h" #include "Utility.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #ifndef WS_EX_LAYERED # define WS_EX_LAYERED 0x00080000 #endif #ifndef WS_EX_NOACTIVATE # define WS_EX_NOACTIVATE 0x08000000L #endif #ifndef LWA_ALPHA # define LWA_ALPHA 0x00000002 #endif #ifndef ULW_ALPHA # define ULW_ALPHA 0x00000002 #endif #ifndef AC_SRC_ALPHA # define AC_SRC_ALPHA 0x01 #endif std::map<HWND, tagCtrlInfo> CImgDialogBase::s_mpCtrl; PFN_SetLayeredWindowAttributes CImgDialogBase::s_pfnSetLayeredWindowAttributes = NULL; PFN_UpdateLayeredWindow CImgDialogBase::s_pfnUpdateLayeredWindow = NULL; PFN_GetGUIThreadInfo CImgDialogBase::s_pfnGetGUIThreadInfo = NULL; ///////////////////////////////////////////////////////////////////////////// // CImgDialogBase dialog CImgDialogBase::CImgDialogBase( UINT nIDD , LPCWSTR lpszFile , CWnd* pParent ) : CDialog( nIDD, pParent) , m_pImage( new Image(lpszFile) ) , m_hFakeWnd(NULL) , m_bIsRefreshing(FALSE) , m_nAlpha(0) , m_bShown(FALSE) { //{{AFX_DATA_INIT(CImgDialogBase) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_strWndClassName.Format( _T("FakeWnd%X%X%X%d") , GetTickCount() , GetCurrentProcessId() , GetCurrentThreadId() , nIDD ); } CImgDialogBase::CImgDialogBase( UINT nIDD , UINT nImgID , LPCTSTR lpszType , HINSTANCE hResourceModule , CWnd* pParent ) : CDialog( nIDD, pParent) , m_pImage( CUtility::LoadImage( nImgID, lpszType, hResourceModule) ) , m_hFakeWnd(NULL) , m_bIsRefreshing(FALSE) , m_bShown(FALSE) , m_nAlpha(0) { //{{AFX_DATA_INIT(CImgDialogBase) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_strWndClassName.Format( _T("FakeWnd%X%X%X%d") , GetTickCount() , GetCurrentProcessId() , GetCurrentThreadId() , nIDD ); } CImgDialogBase::~CImgDialogBase() { if( m_pImage ) { delete m_pImage; m_pImage = NULL; } } void CImgDialogBase::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CImgDialogBase) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CImgDialogBase, CDialog) //{{AFX_MSG_MAP(CImgDialogBase) ON_WM_LBUTTONDOWN() ON_WM_ERASEBKGND() ON_WM_MOVE() ON_WM_SIZE() ON_WM_SHOWWINDOW() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CImgDialogBase message handlers BOOL CImgDialogBase::OnInitDialog() { CDialog::OnInitDialog(); HMODULE hUser32Dll = ::GetModuleHandle(_T("user32.dll")); ASSERT(hUser32Dll); if( !s_pfnSetLayeredWindowAttributes ) { s_pfnSetLayeredWindowAttributes = (PFN_SetLayeredWindowAttributes)::GetProcAddress( hUser32Dll, "SetLayeredWindowAttributes"); ASSERT(s_pfnSetLayeredWindowAttributes); } if( !s_pfnUpdateLayeredWindow ) { s_pfnUpdateLayeredWindow = (PFN_UpdateLayeredWindow)::GetProcAddress( hUser32Dll, "UpdateLayeredWindow"); ASSERT(s_pfnUpdateLayeredWindow); } if( !s_pfnGetGUIThreadInfo ) { s_pfnGetGUIThreadInfo = (PFN_GetGUIThreadInfo)::GetProcAddress( hUser32Dll, "GetGUIThreadInfo"); ASSERT(s_pfnGetGUIThreadInfo); } if( m_pImage ) { // Set the dialog style ::SetWindowPos( GetSafeHwnd() , NULL , 0 , 0 , m_pImage->GetWidth() , m_pImage->GetHeight() , SWP_NOMOVE | SWP_NOZORDER ); ::SetWindowLong( m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); BYTE bTran = 0x05; s_pfnSetLayeredWindowAttributes( m_hWnd, 0, bTran, LWA_ALPHA); CreateFakeWnd(); HookControlUpdate(GetSafeHwnd()); } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CImgDialogBase::OnLButtonDown(UINT nFlags, CPoint point) { ::SendMessage( GetSafeHwnd(), WM_SYSCOMMAND, 0xF012, 0); CDialog::OnLButtonDown(nFlags, point); } BOOL CImgDialogBase::OnEraseBkgnd(CDC* pDC) { return TRUE; } void CImgDialogBase::OnMove(int x, int y) { CDialog::OnMove(x, y); if( ::IsWindow(m_hFakeWnd) ) { ::SetWindowPos( m_hFakeWnd , HWND_TOP , x , y , 0 , 0 , SWP_NOSIZE ); } } void CImgDialogBase::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); if( ::IsWindow(m_hFakeWnd) ) { ::SetWindowPos( m_hFakeWnd , HWND_TOP , 0 , 0 , cx , cy , SWP_NOMOVE ); } } void CImgDialogBase::OnShowWindow(BOOL bShow, UINT nStatus) { CDialog::OnShowWindow(bShow, nStatus); ::ShowWindow( m_hFakeWnd, bShow ? SW_SHOWNA : SW_HIDE); if( !m_bShown ) { m_bShown = TRUE; AfxBeginThread( (AFX_THREADPROC)ShowMotionThread, this); } } //------------------------------------------------------------------------- // Function Name :DestoryFakeWnd // Parameter(s) : // Return : // Create :2007-5-8 11:43 Jerry.Wang // Memo :Destory the fake wnd //------------------------------------------------------------------------- void CImgDialogBase::DestoryFakeWnd(void) { if( m_hFakeWnd != NULL ) { ::DestroyWindow(m_hFakeWnd); m_hFakeWnd = NULL; ::UnregisterClass( m_strWndClassName, ::GetModuleHandle(NULL) ); } } //------------------------------------------------------------------------- // Function Name :CreateFakeWnd // Parameter(s) : // Return : // Create :2007-5-7 18:50 Jerry.Wang // Memo :create the fake window //------------------------------------------------------------------------- void CImgDialogBase::CreateFakeWnd(void) { DestoryFakeWnd(); WNDCLASSEX wcex; memset(&wcex, 0, sizeof(wcex)); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = ::DefWindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = ::GetModuleHandle(NULL); wcex.hIcon = NULL; wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszMenuName = NULL; wcex.lpszClassName = m_strWndClassName; wcex.hIconSm = NULL; VERIFY( RegisterClassEx(&wcex) ); CRect rc; GetWindowRect(rc); m_hFakeWnd = ::CreateWindowEx( WS_EX_WINDOWEDGE | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE , m_strWndClassName , NULL , WS_VISIBLE | WS_POPUP , rc.left , rc.top , rc.Width() , rc.Height() , GetSafeHwnd() , NULL , ::GetModuleHandle(NULL) , NULL ); ASSERT( m_hFakeWnd != NULL ); } void CImgDialogBase::HookControlUpdate(HWND hWnd) { tagCtrlInfo stCtrlInfo = {0}; stCtrlInfo.pImgDlg = this; stCtrlInfo.pWndProc = (WNDPROC)::GetWindowLong( hWnd, GWL_WNDPROC); s_mpCtrl[hWnd] = stCtrlInfo; ::SetWindowLong( hWnd, GWL_WNDPROC, (LONG)(&CImgDialogBase::CtrlWndProc) ); HWND hChild = ::GetWindow( hWnd, GW_CHILD); while(hChild) { HookControlUpdate(hChild); hChild = ::GetWindow( hChild, GW_HWNDNEXT); } } void CImgDialogBase::UnhookControlUpdate(HWND hWnd) { if( !::IsWindow(hWnd) ) return; std::map<HWND, tagCtrlInfo>::iterator iter; iter = s_mpCtrl.find(hWnd); if( iter != s_mpCtrl.end() ) s_mpCtrl.erase(iter); HWND hChild = ::GetWindow( hWnd, GW_CHILD); while(hChild) { UnhookControlUpdate(hChild); hChild = ::GetWindow( hChild, GW_HWNDNEXT); } } LRESULT CALLBACK CImgDialogBase::CtrlWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { std::map<HWND, tagCtrlInfo>::iterator iter; iter = s_mpCtrl.find(hWnd); if( iter == s_mpCtrl.end() ) return ::DefWindowProc( hWnd, nMsg, wParam, lParam); LRESULT lResult = ::CallWindowProc( iter->second.pWndProc, hWnd, nMsg, wParam, lParam); switch (nMsg) { case WM_PAINT: case WM_CAPTURECHANGED: //case WM_NCPAINT: //case WM_CTLCOLOR: case WM_CTLCOLOREDIT: case WM_CTLCOLORBTN: case WM_CTLCOLORSTATIC: case WM_CTLCOLORMSGBOX: case WM_CTLCOLORDLG: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORSCROLLBAR: { iter->second.pImgDlg->Refresh(); break; } default: break; } return lResult; } void CImgDialogBase::Refresh(void) { if( !IsWindow(m_hFakeWnd) ) return; if( m_bIsRefreshing ) return; m_bIsRefreshing = TRUE; RECT rc; ::GetWindowRect( m_hFakeWnd, &rc); POINT ptSrc = { 0, 0}; POINT ptWinPos = { rc.left, rc.top}; SIZE szWin = { m_pImage->GetWidth(), m_pImage->GetHeight() }; BLENDFUNCTION stBlend = {AC_SRC_OVER, 0, m_nAlpha, AC_SRC_ALPHA}; HDC hDC = ::GetDC(NULL); HDC hdcMemory = ::CreateCompatibleDC(hDC); BITMAPINFOHEADER stBmpInfoHeader = { 0 }; int nBytesPerLine = ((szWin.cx * 32 + 31) & (~31)) >> 3; stBmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); stBmpInfoHeader.biWidth = szWin.cx; stBmpInfoHeader.biHeight = szWin.cy; stBmpInfoHeader.biPlanes = 1; stBmpInfoHeader.biBitCount = 32; stBmpInfoHeader.biCompression = BI_RGB; stBmpInfoHeader.biClrUsed = 0; stBmpInfoHeader.biSizeImage = nBytesPerLine * szWin.cy; PUINT32 pvBits = NULL; HBITMAP hbmpMem = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader, DIB_RGB_COLORS, (LPVOID*)&pvBits, NULL, 0); ASSERT(hbmpMem != NULL); if(hbmpMem) { HGDIOBJ hbmpOld = ::SelectObject( hdcMemory, hbmpMem); { Graphics graph(hdcMemory); graph.SetSmoothingMode(SmoothingModeNone); graph.DrawImage( m_pImage, 0, 0, szWin.cx, szWin.cy); // Draw all the controls HWND hwndChild = ::GetWindow( GetSafeHwnd(), GW_CHILD); while(hwndChild) { DrawCtrl( graph, hDC, hwndChild); hwndChild = ::GetWindow( hwndChild, GW_HWNDNEXT); } DrawCaret(graph); } s_pfnUpdateLayeredWindow( m_hFakeWnd , hDC , &ptWinPos , &szWin , hdcMemory , &ptSrc , 0 , &stBlend , ULW_ALPHA ); ::SelectObject( hdcMemory, hbmpOld); ::DeleteObject(hbmpMem); } ::DeleteDC(hdcMemory); ::DeleteDC(hDC); m_bIsRefreshing = FALSE; } void CImgDialogBase::DrawCtrl( Graphics & graphics, HDC hDC, HWND hWnd) { if( !::IsWindow(hWnd) ) return; RECT rc; ::GetWindowRect( hWnd, &rc); ScreenToClient(&rc); HDC hdcMemory = ::CreateCompatibleDC(hDC); HBITMAP hBitmap = ::CreateCompatibleBitmap( hDC, rc.right - rc.left, rc.bottom - rc.top); HGDIOBJ hbmpOld = ::SelectObject( hdcMemory, hBitmap); ::SendMessage( hWnd, WM_PRINT, (WPARAM)hdcMemory, (LPARAM)PRF_NONCLIENT | PRF_CLIENT | PRF_CHILDREN | PRF_CHECKVISIBLE | PRF_ERASEBKGND | PRF_OWNED); Bitmap bitmap( hBitmap, NULL); graphics.DrawImage( &bitmap, rc.left, rc.top); ::SelectObject( hdcMemory, hbmpOld); ::DeleteDC(hdcMemory); ::DeleteObject(hBitmap); } void CImgDialogBase::DrawCaret(Graphics & graph) { GUITHREADINFO stThreadInfo = {0}; stThreadInfo.cbSize = sizeof(GUITHREADINFO); BOOL bRet = s_pfnGetGUIThreadInfo( ::GetCurrentThreadId(), &stThreadInfo); if( !bRet || !::IsWindow(stThreadInfo.hwndCaret) ) return; POINT ptCaret = { stThreadInfo.rcCaret.left, stThreadInfo.rcCaret.top}; int nHeight = stThreadInfo.rcCaret.bottom - stThreadInfo.rcCaret.top; ::ClientToScreen( stThreadInfo.hwndCaret, &ptCaret); ::ScreenToClient( m_hFakeWnd, &ptCaret); Pen pen( Color::Black, 1.0f); graph.DrawLine( &pen , ptCaret.x , ptCaret.y , ptCaret.x , ptCaret.y + nHeight ); } UINT __cdecl CImgDialogBase::ShowMotionThread( LPVOID pParam ) { CImgDialogBase * pThis = static_cast<CImgDialogBase*>(pParam); while (pThis->m_nAlpha < 255) { pThis->m_nAlpha += 30; if( pThis->m_nAlpha > 255 ) pThis->m_nAlpha = 255; ::SendMessage( pThis->GetSafeHwnd(), WM_PAINT, 0, 0); Sleep(60); } return 0; } void CImgDialogBase::PostNcDestroy() { UnhookControlUpdate(GetSafeHwnd()); DestoryFakeWnd(); CDialog::PostNcDestroy(); }