我在網上看到很多屏幕截取的文章,相信大家也看過不少。人類每一次的進步總是建立在別人的基礎之上,我今天要做得是如何將一個窗口動態地顯示在另外一個窗口上。
方法很簡單,核心算法是要完成對一個窗口DC顯示到另外一個窗口的DC,為了方便代碼的重用,我特地把它放到一個自己編寫的函數:
BOOL CShow_WindowDCView::Show_WindowDC(CWnd *pWndDest /*目標窗口的wnd指針*/,
CWnd *pWndSrc /*源窗口*/)
{
//當然正規點還得判斷它IsKindof(“CWnd”),這裡我就偷懶了
if(pWndDest==NULL || pWndSrc==NULL) return FALSE;
CRect SrcRect;
pWndSrc->GetWindowRect(&SrcRect);
// 內存設備描述表
HDC hSrcDC, hMemDC;
// 位圖句柄
HBITMAP hBitmap, hOldBitmap;
// 位圖寬度和高度
int nWidth, nHeight;
pWndSrc->Invalidate();
hSrcDC=pWndSrc->GetDC()->m_hDC;
// 創建一個與源窗口設備描述表兼容的內存設備描述表
hMemDC = CreateCompatibleDC(hSrcDC);
nWidth = SrcRect.Width();
nHeight = SrcRect.Height();
// 創建一個與源窗口設備描述表兼容的位圖
hBitmap = CreateCompatibleBitmap(hSrcDC, nWidth, nHeight);
// 把新位圖選到內存設備描述表中
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
// 把屏幕設備描述表拷貝到內存設備描述表中
BitBlt(hMemDC, 0, 0, nWidth, nHeight,hSrcDC, 0, 0, SRCCOPY);
//得到位圖的句柄
hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
CRect DestRect;
GetWindowRect(&DestRect);
CDC dcMem;
//創建一個與目標窗口設備描述表兼容的位圖
dcMem.CreateCompatibleDC(GetDC());
HBITMAP poldBitmap=(HBITMAP)SelectObject(dcMem.m_hDC,hBitmap);
GetDC()->StretchBlt(0,0 ,
DestRect.Width(),
DestRect.Height(),
&dcMem,0 ,0,
nWidth,nHeight,
SRCCOPY); //顯示位圖
//善後工作
DeleteDC(hSrcDC);
DeleteDC(hMemDC);
dcMem.SelectObject(poldBitmap);
dcMem.DeleteDC();
return TRUE;
}
有了這個函數的支持,其他實現就簡單了。要實現動態的獲取一個窗口的DC只要加一個計時器
SetTimer(1,100,NULL);
在計時器裡放一個刷新語句就可以了。
Invalidate();
另外,為了消除不必要的閃爍,還要在重載WM_ERASEBKGND消息,只要在對應的 OnEraseBkgnd(CDC* pDC) 添加 return TRUE,其它都不要,最後在 OnDraw(CDC* pDC)添加:
CWnd *source=FindWindow("GeminiWindowClass",NULL);//搜索窗口
這裡搜索的是我的realone窗口
BOOL rst=Show_WindowDC(this,source);
為了程序的美觀,我去掉菜單,工具欄和狀態欄,具體可以參考我的源程序。程序運行如下:
快照
結束語
程序本身當然還有不少問題,比如說只能找一個具體的窗口,不靈活,我介紹大家一篇文章,《怎樣編寫一個類Spy++的搜索窗口程序》,相信能解決這個問題。當程序運行的時候要保證源窗口在可見狀態,否則,是無法正常顯示的。也借這個機會,希望大家有更好的想法可以在這裡提出來,該程序在XP+V6.0下調試通過。
本文配套源碼