www.gusucode.com > VC++使用BMP位图换肤实现液晶电子钟-源码程序 > VC++使用BMP位图换肤实现液晶电子钟-源码程序/code/TransparentWnd.cpp

    //********************************************************************************
//* TransparentWindow.CPP
//* Download by http://www.NewXing.com
//* A transparent window class.
//*
//* Based on the idea of Jason Wylie ,Franz Polzer,Luo yun bin
//* e9225140@student.tuwien.ac.at
//* (C) 2002 by 王鹏
//*
//* Write to me:	mailwp@21cn.com
//********************************************************************************


#include "stdafx.h"
#include "TransparentWnd.h"
#include "Dib.h"
#include "resource.h"

#include <assert.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define WM_LIBEN WM_USER+994

CString GetCurPath()
{
	TCHAR exeFullPath[MAX_PATH];
	CString strPath;
	GetModuleFileName(NULL,exeFullPath,MAX_PATH);
	strPath.Format("%s", exeFullPath);
	strPath = strPath.Left(strPath.ReverseFind('\\'));

	return strPath;
}


//********************************************************************************
// LoadBMPImage	- Loads a BMP file and creates a bitmap GDI object
//		  also creates logical palette for it.
// Returns	- TRUE for success
// sBMPFile	- Full path of the BMP file
// bitmap	- The bitmap object to initialize
// pPal		- Will hold the logical palette. Can be NULL
//********************************************************************************
BOOL LoadBMPImage( LPCTSTR sBMPFile, CBitmap& bitmap, CPalette *pPal )
{
	CFile file;
	if( !file.Open( sBMPFile, CFile::modeRead) )
		return FALSE;
	
	BITMAPFILEHEADER bmfHeader;
	
	// Read file header
	if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
		return FALSE;
	
	// File type should be 'BM'
	if (bmfHeader.bfType != ((WORD) ('M' << 8) | 'B'))
		return FALSE;
	
	// Get length of the remainder of the file and allocate memory
	DWORD nPackedDIBLen = file.GetLength() - sizeof(BITMAPFILEHEADER);
	HGLOBAL hDIB = ::GlobalAlloc(GMEM_FIXED, nPackedDIBLen);
	if (hDIB == 0)
		return FALSE;
	
	// Read the remainder of the bitmap file.
	if (file.ReadHuge((LPSTR)hDIB, nPackedDIBLen) != nPackedDIBLen )
	{
		::GlobalFree(hDIB);
		return FALSE;
	}
	
	
	BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
	BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
	
	// If bmiHeader.biClrUsed is zero we have to infer the number
	// of colors from the number of bits used to specify it.
	int nColors = bmiHeader.biClrUsed ? bmiHeader.biClrUsed : 
	1 << bmiHeader.biBitCount;
	
	LPVOID lpDIBBits;
	if( bmInfo.bmiHeader.biBitCount > 8 )
		lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors + bmInfo.bmiHeader.biClrUsed) + 
		((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
	else
		lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
	
	// Create the logical palette
	if( pPal != NULL )
	{
		// Create the palette
		if( nColors <= 256 )
		{
			UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
			LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
			
			pLP->palVersion = 0x300;
			pLP->palNumEntries = nColors;
			
			for( int i=0; i < nColors; i++)
			{
				pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
				pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
				pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
				pLP->palPalEntry[i].peFlags = 0;
			}
			
			pPal->CreatePalette( pLP );
			
			delete[] pLP;
		}
	}
	
	CClientDC dc(NULL);
	CPalette* pOldPalette = NULL;
	if( pPal )
	{
		pOldPalette = dc.SelectPalette( pPal, FALSE );
		dc.RealizePalette();
	}
	
	HBITMAP hBmp = CreateDIBitmap( dc.m_hDC,		// handle to device context 
		&bmiHeader,	// pointer to bitmap size and format data 
		CBM_INIT,	// initialization flag 
		lpDIBBits,	// pointer to initialization data 
		&bmInfo,	// pointer to bitmap color-format data 
		DIB_RGB_COLORS);		// color-data usage 
	bitmap.Attach( hBmp );
	
	if( pOldPalette )
		dc.SelectPalette( pOldPalette, FALSE );
	
	::GlobalFree(hDIB);
	return TRUE;
}

//********************************************************************************
//       function:FindBmpFile()
//       strParent   search path
//       1.search bmp file
//       2.create random number
//********************************************************************************
void CTransparentWnd::FindBmpFile(CString strPath)
{
	int nFilecount1=0;  // 背景
	int nFilecount2=0;  // 数字
	int nFilter;
	nFilter=GetCurPath().GetLength()+10;
	CFileFind finder;
	
	// build a string with wildcards
	CString strWildcard(strPath);
	strWildcard += _T("\\*.bmp");
	try
	{
		//--------------------------------------------------------------
		// start working for filescount
		//--------------------------------------------------------------
		BOOL bWorking = finder.FindFile(strWildcard);
		
		while (bWorking)
		{
			bWorking = finder.FindNextFile();
			
			// skip . and .. files; otherwise, we'd
			// recur infinitely!
			
			if (finder.IsDots())
				continue;
			
			// if it's NOT a directory, recursively search it
			
			if (!finder.IsDirectory())
			{
				if (finder.GetFilePath().GetLength() > nFilter)
					nFilecount1++;   //background
				else
					nFilecount2++;   //number
			}
		}
		DWORD dwTick=GetTickCount();
		//random the image
		nFilecount1=(int)(dwTick%(nFilecount1-1));
		nFilecount2=(int)(dwTick%(nFilecount2-1));
		//--------------------------------------------------------------
		//  获得具体的图片
		//--------------------------------------------------------------
		bWorking = finder.FindFile(strWildcard);
		int m=0;
		int n=0;
		while (bWorking)  //2
		{
			bWorking = finder.FindNextFile();
			
			// skip . and .. files; otherwise, we'd
			// recur infinitely!
			
			if (finder.IsDots())
				continue;
			
			// if it's NOT a directory, recursively search it
			
			if (!finder.IsDirectory())
			{
				if (finder.GetFilePath().GetLength() > nFilter)
				{					
				    if (m==nFilecount1)
					m_szBmpFile=finder.GetFilePath();
					m++;
				}
				else
				{					
				    if (n==nFilecount2)
					m_szNumFile=finder.GetFilePath();
					n++;
				}
			}
		}//2
	}
	catch(...)
	{
		
	}
	
}
//********************************************************************************
//* Constructor
//********************************************************************************
CTransparentWnd::CTransparentWnd()
{
	
	m_nh1=0;
	m_nh2=0;
	m_nm1=0;
	m_nm2=0;
	m_ns1=0;
	m_ns2=0;
}


//********************************************************************************
//* Destructor
//********************************************************************************
CTransparentWnd::~CTransparentWnd()
{
	KillTimer(1);
	
	//AfxPostQuitMessage(0);
	
}


BEGIN_MESSAGE_MAP(CTransparentWnd, CWnd)
//{{AFX_MSG_MAP(CTransparentWnd)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
ON_COMMAND(ID_MIN_ICON, OnMinIcon)
ON_WM_CONTEXTMENU()
ON_COMMAND(ID_CLOSE, OnClose)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_LIBEN,OnLiben)
END_MESSAGE_MAP()


//********************************************************************************
//* CreateTransparent()
//*
//* Creates the main application window transparent
//********************************************************************************

void CTransparentWnd::CreateTransparent(LPCTSTR pTitle)
{
	FindBmpFile(GetCurPath());
    CDib dib(m_szBmpFile);
	
	CRect rect(0,0,dib.m_nWidth,dib.m_nHeight);
	
	
	CreateEx(	WS_EX_TOOLWINDOW,
		AfxRegisterWndClass(0),
		pTitle,
		WS_POPUP | WS_SYSMENU|WS_EX_TOOLWINDOW,
		rect,
		NULL,
		NULL,
		NULL );
	SetupRegion(GetWindowDC());
	//m_BitmapID = BitmapID;
	SetTimer(1,100,NULL);
	
    NOTIFYICONDATA tnd;	
	
	tnd.cbSize=sizeof(NOTIFYICONDATA);
	
	tnd.hWnd=this->m_hWnd;
	
	tnd.uID=IDR_MAINFRAME;
	
	tnd.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
	
	tnd.uCallbackMessage=WM_LIBEN;
	
	tnd.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
	
	strcpy(tnd.szTip,"提示信息");
	
	Shell_NotifyIcon(NIM_ADD,&tnd);
	
	SetWindowPos(
		(GetExStyle() & WS_EX_TOPMOST) ? &CWnd::wndNoTopMost : &CWnd::wndTopMost,
		0,0,0,0,
		SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
	
	HCURSOR hCursor;
	
	// Load a cursor resource that was originally created using
	hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);
	SetCursor(hCursor);	

	//加入WS_EX_LAYERED扩展属性
	SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
		GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
	HINSTANCE hInst = LoadLibrary("User32.DLL"); 
	if(hInst) 
	{ 
		typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD); 
		MYFUNC fun = NULL;
		//取得SetLayeredWindowAttributes函数指针 
		fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
		if(fun)fun(this->GetSafeHwnd(),0,200,2); 
		FreeLibrary(hInst); 
	}
}


//********************************************************************************
//* SetupRegion()
//*
//* Set the Window Region for transparancy outside the mask region
//********************************************************************************
void CTransparentWnd::SetupRegion(CDC *pDC)
{
	CDC					memDC;
	CBitmap			cBitmap;
	CBitmap*		pOldMemBmp = NULL;
	COLORREF		col,maskcol;
	CRect				cRect;
	int					x, y;
	CRgn				wndRgn, rgnTemp;
    int sum;
	GetWindowRect(&cRect);
	
	//cBitmap.LoadBitmap(MaskID);
	LoadBMPImage(m_szBmpFile,cBitmap,NULL);
	memDC.CreateCompatibleDC(pDC);
	pOldMemBmp = memDC.SelectObject(&cBitmap);
	
	wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height());
	
	maskcol=memDC.GetPixel(0, 0);
	for(x=0; x<=cRect.Width(); x++)
	{
		for(y=0; y<=cRect.Height(); y++)
		{
			col = memDC.GetPixel(x, y);
			if(col ==maskcol)
			{
				rgnTemp.CreateRectRgn(x, y, x+1, y+1);
				wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR);
				rgnTemp.DeleteObject();	
			}
			else if (col==0)
			{
				//判断数字的起始黑点
				
				sum=0;
				for(int k=0;k<25;k++) 
				{
					sum=sum+memDC.GetPixel(x, y+k)+memDC.GetPixel(x+109, y+k);
					if (sum!=0)
						break;
				}
				if (sum==0)     //得到起始点x,y
				{
					m_nNumX=x;
					m_nNumY=y;
				}
			}
			
		}
	}
	if (pOldMemBmp) memDC.SelectObject(pOldMemBmp);
	LoadBMPImage(m_szNumFile,m_mapB,NULL);
	SetWindowRgn((HRGN)wndRgn, TRUE);
}

//********************************************************************************
//* CTransparentWnd message handlers
//********************************************************************************

void CTransparentWnd::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CWnd::OnLButtonDown(nFlags, point);
	PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x,point.y));
}

BOOL CTransparentWnd::OnEraseBkgnd(CDC* pDC) 
{
	CRect	rect;
	GetWindowRect(&rect);
	
	CDC memDC;
	CBitmap			cBitmap;
	CBitmap*		pOldMemBmp = NULL;
	
	LoadBMPImage(m_szBmpFile,cBitmap,NULL);
	memDC.CreateCompatibleDC(pDC);
	pOldMemBmp = memDC.SelectObject(&cBitmap);
	pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
	
	if (pOldMemBmp) memDC.SelectObject( pOldMemBmp );	
	
	return TRUE;
}

//********************************************************************************
//   draw the current time
//********************************************************************************
void CTransparentWnd::OnPaint()
{
	CPaintDC dc(this);
	
	CDC mapDC;
	mapDC.CreateCompatibleDC( &dc );
	CBitmap* pOB = mapDC.SelectObject( &m_mapB );
	
	dc.BitBlt( m_nNumX, m_nNumY, 2, 25, &mapDC, 160, 0, SRCCOPY );
    
	dc.BitBlt( m_nNumX+70, m_nNumY, 8, 25, &mapDC, 150, 0, SRCCOPY );
    //秒
	dc.BitBlt( m_nNumX+78, m_nNumY, 15, 25, &mapDC, m_ns1*15, 0, SRCCOPY );
	dc.BitBlt( m_nNumX+93, m_nNumY, 15, 25, &mapDC, m_ns2*15, 0, SRCCOPY );
    //时
	dc.BitBlt( m_nNumX+2, m_nNumY, 15, 25, &mapDC, m_nh1*15, 0, SRCCOPY );
	dc.BitBlt( m_nNumX+17, m_nNumY, 15, 25, &mapDC, m_nh2*15, 0, SRCCOPY );
	//:
	dc.BitBlt( m_nNumX+32, m_nNumY, 8, 25, &mapDC, 150, 0, SRCCOPY );
    //分
	dc.BitBlt( m_nNumX+40, m_nNumY, 15, 25, &mapDC, m_nm1*15, 0, SRCCOPY );
	dc.BitBlt( m_nNumX+55, m_nNumY, 15, 25, &mapDC, m_nm2*15, 0, SRCCOPY );
	//:	
	dc.BitBlt( m_nNumX+108, m_nNumY, 2, 25, &mapDC, 150, 0, SRCCOPY );
	
	mapDC.SelectObject( pOB );	
}

//********************************************************************************
//   Get the Current time then set value the mambervar
//   If the time changed ,repaint it,otherwise return
//********************************************************************************
void CTransparentWnd::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	CTime ctCurrentTime;
	ctCurrentTime = CTime::GetCurrentTime();
	int h=ctCurrentTime.GetHour();
	//int y=ctCurrentTime.GetYear();
	//int m=ctCurrentTime.GetMonth();
	//int d=ctCurrentTime.GetDay();
	int f=ctCurrentTime.GetMinute();
	int s=ctCurrentTime.GetSecond();
	if (m_nSecond==s)
		return;
	else
		m_nSecond=s;
	
	m_ns1=m_nSecond/10;
	m_ns2=m_nSecond%10;
	
	m_nh1=h/10;
	m_nh2=h%10;
	
	
	m_nm1=f/10;
	m_nm2=f%10;
	
	
	//只重绘时钟区域
	Invalidate(FALSE);
	
	CWnd::OnTimer(nIDEvent);
}

//********************************************************************************
//   the tray icon message loop
//********************************************************************************
void CTransparentWnd::OnLiben(WPARAM wParam,LPARAM lParam)
{	
	if(wParam!=IDR_MAINFRAME)
		return;
    switch(lParam)
    {
	case WM_RBUTTONUP://右键起来时弹出快捷菜单,这里只有一个“关闭”
		{
			
			LPPOINT lpoint=new tagPOINT;
			::GetCursorPos(lpoint);//得到鼠标位置
			CMenu *menu;
			CMenu PopMenu;
			PopMenu.LoadMenu(IDR_MENU_POPUP);
			menu = PopMenu.GetSubMenu (0);
			//确定弹出式菜单的位置
			menu->TrackPopupMenu(TPM_LEFTALIGN,lpoint->x,lpoint->y,this);
			//资源回收
			HMENU hmenu=menu->Detach();
			menu->DestroyMenu();
			delete lpoint;
		}
		break;
    case WM_LBUTTONDBLCLK://双击左键的处理
		{
			this->ShowWindow(SW_SHOW);//简单的显示主窗口完事儿
		}
		break;
    }
    return;	
}

void CTransparentWnd::OnMinIcon() 
{
	ShowWindow(SW_HIDE);
}
//********************************************************************************
// Get the mouse pos and draw the pop menu
//********************************************************************************
void CTransparentWnd::OnContextMenu(CWnd* pWnd, CPoint point) 
{
    CMenu PopMenu;
	CMenu *pMenu;
	
	LPPOINT lpoint=new tagPOINT;
	::GetCursorPos(lpoint);//得到鼠标位置
	
	CPoint pt;
	pt= point ;
	
	PopMenu.LoadMenu(IDR_MENU_POPUP);
	ClientToScreen (&pt);
	// show the menu (returns, when menu is closed again!)
	pMenu = PopMenu.GetSubMenu (0);
	pMenu->TrackPopupMenu (TPM_LEFTALIGN,lpoint->x,lpoint->y,this);
}
//********************************************************************************
// When the App exit,delete the tray icon
//********************************************************************************
void CTransparentWnd::OnClose() 
{
	NOTIFYICONDATA tnid;
	
	tnid.cbSize=sizeof(NOTIFYICONDATA);
	
	tnid.hWnd=this->m_hWnd;
	
	tnid.uID=IDR_MAINFRAME;//保证删除的是我们的图标
	
	Shell_NotifyIcon(NIM_DELETE,&tnid);
	
	SendMessage(WM_CLOSE,0,0);
}


BOOL CTransparentWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	// TODO: Add your specialized code here and/or call the base class
	return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}