#include "stdafx.h" #include "SplashScreenEx.h" #ifndef AW_HIDE #define AW_HIDE 0x00010000 #define AW_BLEND 0x00080000 #endif #ifndef CS_DROPSHADOW #define CS_DROPSHADOW 0x00020000 #endif // CSplashScreenEx IMPLEMENT_DYNAMIC(CSplashScreenEx, CWnd) CSplashScreenEx::CSplashScreenEx() { m_pWndParent=NULL; m_strText=""; m_hRegion=0; m_nBitmapWidth=0; m_nBitmapHeight=0; m_nxPos=0; m_nyPos=0; m_dwStyle=0; m_rcText.SetRect(0,0,0,0); m_crTextColor=RGB(0,0,0); m_uTextFormat=DT_CENTER | DT_VCENTER | DT_WORDBREAK; HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL")); if (hUser32!=NULL) m_fnAnimateWindow = (FN_ANIMATE_WINDOW)GetProcAddress(hUser32, _T("AnimateWindow")); else m_fnAnimateWindow = NULL; SetTextDefaultFont(); } CSplashScreenEx::~CSplashScreenEx() { } BOOL CSplashScreenEx::Create(CWnd *pWndParent,LPCTSTR szText,DWORD dwStyle) { ASSERT(pWndParent!=NULL); m_pWndParent = pWndParent; if (szText!=NULL) m_strText = szText; else m_strText=""; m_dwStyle = dwStyle; WNDCLASSEX wcx; wcx.cbSize = sizeof(wcx); wcx.lpfnWndProc = AfxWndProc; wcx.style = CS_DBLCLKS|CS_SAVEBITS; wcx.cbClsExtra = 0; wcx.cbWndExtra = 0; wcx.hInstance = AfxGetInstanceHandle(); wcx.hIcon = NULL; wcx.hCursor = LoadCursor(NULL,IDC_ARROW); wcx.hbrBackground=::GetSysColorBrush(COLOR_WINDOW); wcx.lpszMenuName = NULL; wcx.lpszClassName = "SplashScreenExClass"; wcx.hIconSm = NULL; if (m_dwStyle & CSS_SHADOW) wcx.style|=CS_DROPSHADOW; ATOM classAtom = RegisterClassEx(&wcx); // didn't work? try not using dropshadow (may not be supported) if (classAtom==NULL) { if (m_dwStyle & CSS_SHADOW) { wcx.style &= ~CS_DROPSHADOW; classAtom = RegisterClassEx(&wcx); } else return FALSE; } if (!CreateEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,"SplashScreenExClass",NULL,WS_POPUP,0,0,0,0,pWndParent->m_hWnd,NULL)) return FALSE; return TRUE; } BOOL CSplashScreenEx::SetBitmap(UINT nBitmapID,short red,short green,short blue) { BITMAP bm; m_bitmap.DeleteObject(); if (!m_bitmap.LoadBitmap(nBitmapID)) return FALSE; GetObject(m_bitmap.GetSafeHandle(), sizeof(bm), &bm); m_nBitmapWidth=bm.bmWidth; m_nBitmapHeight=bm.bmHeight; m_rcText.SetRect(0,0,bm.bmWidth,bm.bmHeight); if (m_dwStyle & CSS_CENTERSCREEN) { m_nxPos=(GetSystemMetrics(SM_CXFULLSCREEN)-bm.bmWidth)/2; m_nyPos=(GetSystemMetrics(SM_CYFULLSCREEN)-bm.bmHeight)/2; } else if (m_dwStyle & CSS_CENTERAPP) { CRect rcParentWindow; ASSERT(m_pWndParent!=NULL); m_pWndParent->GetWindowRect(&rcParentWindow); m_nxPos=rcParentWindow.left+(rcParentWindow.right-rcParentWindow.left-bm.bmWidth)/2; m_nyPos=rcParentWindow.top+(rcParentWindow.bottom-rcParentWindow.top-bm.bmHeight)/2; } if (red!=-1 && green!=-1 && blue!=-1) { m_hRegion=CreateRgnFromBitmap((HBITMAP)m_bitmap.GetSafeHandle(),RGB(red,green,blue)); SetWindowRgn(m_hRegion, TRUE); } return TRUE; } BOOL CSplashScreenEx::SetBitmap(LPCTSTR szFileName,short red,short green,short blue) { BITMAP bm; HBITMAP hBmp; hBmp=(HBITMAP)::LoadImage(AfxGetInstanceHandle(),szFileName,IMAGE_BITMAP,0,0, LR_LOADFROMFILE); if (!hBmp) return FALSE; m_bitmap.DeleteObject(); m_bitmap.Attach(hBmp); GetObject(m_bitmap.GetSafeHandle(), sizeof(bm), &bm); m_nBitmapWidth=bm.bmWidth; m_nBitmapHeight=bm.bmHeight; m_rcText.SetRect(0,0,bm.bmWidth,bm.bmHeight); if (m_dwStyle & CSS_CENTERSCREEN) { m_nxPos=(GetSystemMetrics(SM_CXFULLSCREEN)-bm.bmWidth)/2; m_nyPos=(GetSystemMetrics(SM_CYFULLSCREEN)-bm.bmHeight)/2; } else if (m_dwStyle & CSS_CENTERAPP) { CRect rcParentWindow; ASSERT(m_pWndParent!=NULL); m_pWndParent->GetWindowRect(&rcParentWindow); m_nxPos=rcParentWindow.left+(rcParentWindow.right-rcParentWindow.left-bm.bmWidth)/2; m_nyPos=rcParentWindow.top+(rcParentWindow.bottom-rcParentWindow.top-bm.bmHeight)/2; } if (red!=-1 && green!=-1 && blue!=-1) { m_hRegion=CreateRgnFromBitmap((HBITMAP)m_bitmap.GetSafeHandle(),RGB(red,green,blue)); SetWindowRgn(m_hRegion,TRUE); } return TRUE; } void CSplashScreenEx::SetTextFont(LPCTSTR szFont,int nSize,int nStyle) { LOGFONT lf; m_myFont.DeleteObject(); m_myFont.CreatePointFont(nSize,szFont); m_myFont.GetLogFont(&lf); if (nStyle & CSS_TEXT_BOLD) lf.lfWeight = FW_BOLD; else lf.lfWeight = FW_NORMAL; if (nStyle & CSS_TEXT_ITALIC) lf.lfItalic=TRUE; else lf.lfItalic=FALSE; if (nStyle & CSS_TEXT_UNDERLINE) lf.lfUnderline=TRUE; else lf.lfUnderline=FALSE; m_myFont.DeleteObject(); m_myFont.CreateFontIndirect(&lf); } void CSplashScreenEx::SetTextDefaultFont() { LOGFONT lf; CFont *myFont=CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT)); myFont->GetLogFont(&lf); m_myFont.DeleteObject(); m_myFont.CreateFontIndirect(&lf); } void CSplashScreenEx::SetText(LPCTSTR szText) { m_strText=szText; RedrawWindow(); } void CSplashScreenEx::SetTextColor(COLORREF crTextColor) { m_crTextColor=crTextColor; RedrawWindow(); } void CSplashScreenEx::SetTextRect(CRect& rcText) { m_rcText=rcText; RedrawWindow(); } void CSplashScreenEx::SetTextFormat(UINT uTextFormat) { m_uTextFormat=uTextFormat; } void CSplashScreenEx::Show() { SetWindowPos(NULL,m_nxPos,m_nyPos,m_nBitmapWidth,m_nBitmapHeight,SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE); if ((m_dwStyle & CSS_FADEIN) && (m_fnAnimateWindow!=NULL)) { m_fnAnimateWindow(m_hWnd,400,AW_BLEND); } else ShowWindow(SW_SHOW); } void CSplashScreenEx::Hide() { if ((m_dwStyle & CSS_FADEOUT) && (m_fnAnimateWindow!=NULL)) m_fnAnimateWindow(m_hWnd,200,AW_HIDE | AW_BLEND); else ShowWindow(SW_HIDE); DestroyWindow(); } HRGN CSplashScreenEx::CreateRgnFromBitmap(HBITMAP hBmp, COLORREF color) { // this code is written by Davide Pizzolato if (!hBmp) return NULL; BITMAP bm; GetObject( hBmp, sizeof(BITMAP), &bm ); // get bitmap attributes CDC dcBmp; dcBmp.CreateCompatibleDC(GetDC()); //Creates a memory device context for the bitmap dcBmp.SelectObject(hBmp); //selects the bitmap in the device context const DWORD RDHDR = sizeof(RGNDATAHEADER); const DWORD MAXBUF = 40; // size of one block in RECTs // (i.e. MAXBUF*sizeof(RECT) in bytes) LPRECT pRects; DWORD cBlocks = 0; // number of allocated blocks INT i, j; // current position in mask image INT first = 0; // left position of current scan line // where mask was found bool wasfirst = false; // set when if mask was found in current scan line bool ismask; // set when current color is mask color // allocate memory for region data RGNDATAHEADER* pRgnData = (RGNDATAHEADER*)new BYTE[ RDHDR + ++cBlocks * MAXBUF * sizeof(RECT) ]; memset( pRgnData, 0, RDHDR + cBlocks * MAXBUF * sizeof(RECT) ); // fill it by default pRgnData->dwSize = RDHDR; pRgnData->iType = RDH_RECTANGLES; pRgnData->nCount = 0; for ( i = 0; i < bm.bmHeight; i++ ) for ( j = 0; j < bm.bmWidth; j++ ){ // get color ismask=(dcBmp.GetPixel(j,bm.bmHeight-i-1)!=color); // place part of scan line as RECT region if transparent color found after mask color or // mask color found at the end of mask image if (wasfirst && ((ismask && (j==(bm.bmWidth-1)))||(ismask ^ (jnCount++ ] = CRect( first, bm.bmHeight - i - 1, j+(j==(bm.bmWidth-1)), bm.bmHeight - i ); // if buffer full reallocate it if ( pRgnData->nCount >= cBlocks * MAXBUF ){ LPBYTE pRgnDataNew = new BYTE[ RDHDR + ++cBlocks * MAXBUF * sizeof(RECT) ]; memcpy( pRgnDataNew, pRgnData, RDHDR + (cBlocks - 1) * MAXBUF * sizeof(RECT) ); delete pRgnData; pRgnData = (RGNDATAHEADER*)pRgnDataNew; } wasfirst = false; } else if ( !wasfirst && ismask ){ // set wasfirst when mask is found first = j; wasfirst = true; } } dcBmp.DeleteDC(); //release the bitmap // create region /* Under WinNT the ExtCreateRegion returns NULL (by Fable@aramszu.net) */ // HRGN hRgn = ExtCreateRegion( NULL, RDHDR + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData ); /* ExtCreateRegion replacement { */ HRGN hRgn=CreateRectRgn(0, 0, 0, 0); ASSERT( hRgn!=NULL ); pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR); for(i=0;i<(int)pRgnData->nCount;i++) { HRGN hr=CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom); VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR)!=ERROR); if (hr) DeleteObject(hr); } ASSERT( hRgn!=NULL ); /* } ExtCreateRegion replacement */ delete pRgnData; return hRgn; } void CSplashScreenEx::DrawWindow(CDC *pDC) { CDC memDC; CBitmap *pOldBitmap; // Blit Background memDC.CreateCompatibleDC(pDC); pOldBitmap=memDC.SelectObject(&m_bitmap); pDC->BitBlt(0,0,m_nBitmapWidth,m_nBitmapHeight,&memDC,0,0,SRCCOPY); memDC.SelectObject(pOldBitmap); // Draw Text CFont *pOldFont; pOldFont=pDC->SelectObject(&m_myFont); pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(m_crTextColor); pDC->DrawText(m_strText,-1,m_rcText,m_uTextFormat); pDC->SelectObject(pOldFont); } BEGIN_MESSAGE_MAP(CSplashScreenEx, CWnd) ON_WM_ERASEBKGND() ON_WM_PAINT() ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient) END_MESSAGE_MAP() // CSplashScreenEx message handlers BOOL CSplashScreenEx::OnEraseBkgnd(CDC* pDC) { return TRUE; } void CSplashScreenEx::OnPaint() { CPaintDC dc(this); // device context for painting DrawWindow(&dc); } LRESULT CSplashScreenEx::OnPrintClient(WPARAM wParam, LPARAM lParam) { CDC* pDC = CDC::FromHandle((HDC)wParam); DrawWindow(pDC); return 1; } void CSplashScreenEx::PostNcDestroy() { CWnd::PostNcDestroy(); delete this; }