/*---------------------------------------
BLOWUP.C -- Video Magnifier Program
(c) Charles Petzold, 1998
---------------------------------------*/#include <windows.h>
#include <stdlib.h> // for abs definition
#include "resource.h"LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName [] = TEXT ("Blowup") ;
HACCEL hAccel ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Blow-Up Mouse Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ; hAccel = LoadAccelerators (hInstance, szAppName) ; while (GetMessage (&msg, NULL, 0, 0))
{
if (!TranslateAccelerator (hwnd, hAccel, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
return msg.wParam ;
}void InvertBlock (HWND hwndScr, HWND hwnd, POINT ptBeg, POINT ptEnd)
{
HDC hdc ; hdc = GetDCEx (hwndScr, NULL, DCX_CACHE | DCX_LOCKWINDOWUPDATE) ;
ClientToScreen (hwnd, &ptBeg) ;
ClientToScreen (hwnd, &ptEnd) ;
PatBlt (hdc, ptBeg.x, ptBeg.y, ptEnd.x - ptBeg.x, ptEnd.y - ptBeg.y,
DSTINVERT) ;
ReleaseDC (hwndScr, hdc) ;
}HBITMAP CopyBitmap (HBITMAP hBitmapSrc)
{
BITMAP bitmap ;
HBITMAP hBitmapDst ;
HDC hdcSrc, hdcDst ; GetObject (hBitmapSrc, sizeof (BITMAP), &bitmap) ;
hBitmapDst = CreateBitmapIndirect (&bitmap) ; hdcSrc = CreateCompatibleDC (NULL) ;
hdcDst = CreateCompatibleDC (NULL) ; SelectObject (hdcSrc, hBitmapSrc) ;
SelectObject (hdcDst, hBitmapDst) ; BitBlt (hdcDst, 0, 0, bitmap.bmWidth, bitmap.bmHeight,
hdcSrc, 0, 0, SRCCOPY) ; DeleteDC (hdcSrc) ;
DeleteDC (hdcDst) ; return hBitmapDst ;
}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bCapturing, bBlocking ;
static HBITMAP hBitmap ;
static HWND hwndScr ;
static POINT ptBeg, ptEnd ;
BITMAP bm ;
HBITMAP hBitmapClip ;
HDC hdc, hdcMem ;
int iEnable ;
PAINTSTRUCT ps ;
RECT rect ; switch (message)
{
case WM_LBUTTONDOWN:
if (!bCapturing)
{
if (LockWindowUpdate (hwndScr = GetDesktopWindow ()))
{
bCapturing = TRUE ;
SetCapture (hwnd) ;
SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
}
else
MessageBeep (0) ;
}
return 0 ; case WM_RBUTTONDOWN:
if (bCapturing)
{
bBlocking = TRUE ;
ptBeg.x = LOWORD (lParam) ;
ptBeg.y = HIWORD (lParam) ;
ptEnd = ptBeg ;
InvertBlock (hwndScr, hwnd, ptBeg, ptEnd) ;
}
return 0 ; case WM_MOUSEMOVE:
if (bBlocking)
{
InvertBlock (hwndScr, hwnd, ptBeg, ptEnd) ;
ptEnd.x = LOWORD (lParam) ;
ptEnd.y = HIWORD (lParam) ;
InvertBlock (hwndScr, hwnd, ptBeg, ptEnd) ;
}
return 0 ; case WM_LBUTTONUP:
case WM_RBUTTONUP:
if (bBlocking)
{
InvertBlock (hwndScr, hwnd, ptBeg, ptEnd) ;
ptEnd.x = LOWORD (lParam) ;
ptEnd.y = HIWORD (lParam) ; if (hBitmap)
{
DeleteObject (hBitmap) ;
hBitmap = NULL ;
} hdc = GetDC (hwnd) ;
hdcMem = CreateCompatibleDC (hdc) ;
hBitmap = CreateCompatibleBitmap (hdc,
abs (ptEnd.x - ptBeg.x),
abs (ptEnd.y - ptBeg.y)) ; SelectObject (hdcMem, hBitmap) ; StretchBlt (hdcMem, 0, 0, abs (ptEnd.x - ptBeg.x),
abs (ptEnd.y - ptBeg.y),
hdc, ptBeg.x, ptBeg.y, ptEnd.x - ptBeg.x,
ptEnd.y - ptBeg.y, SRCCOPY) ; DeleteDC (hdcMem) ;
ReleaseDC (hwnd, hdc) ;
InvalidateRect (hwnd, NULL, TRUE) ;
}
if (bBlocking || bCapturing)
{
bBlocking = bCapturing = FALSE ;
SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
ReleaseCapture () ;
LockWindowUpdate (NULL) ;
}
return 0 ; case WM_INITMENUPOPUP:
iEnable = IsClipboardFormatAvailable (CF_BITMAP) ?
MF_ENABLED : MF_GRAYED ; EnableMenuItem ((HMENU) wParam, IDM_EDIT_PASTE, iEnable) ; iEnable = hBitmap ? MF_ENABLED : MF_GRAYED ; EnableMenuItem ((HMENU) wParam, IDM_EDIT_CUT, iEnable) ;
EnableMenuItem ((HMENU) wParam, IDM_EDIT_COPY, iEnable) ;
EnableMenuItem ((HMENU) wParam, IDM_EDIT_DELETE, iEnable) ;
return 0 ; case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_EDIT_CUT:
case IDM_EDIT_COPY:
if (hBitmap)
{
hBitmapClip = CopyBitmap (hBitmap) ;
OpenClipboard (hwnd) ;
EmptyClipboard () ;
SetClipboardData (CF_BITMAP, hBitmapClip) ;
}
if (LOWORD (wParam) == IDM_EDIT_COPY)
return 0 ;
// fall through for IDM_EDIT_CUT
case IDM_EDIT_DELETE:
if (hBitmap)
{
DeleteObject (hBitmap) ;
hBitmap = NULL ;
}
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ; case IDM_EDIT_PASTE:
if (hBitmap)
{
DeleteObject (hBitmap) ;
hBitmap = NULL ;
}
OpenClipboard (hwnd) ;
hBitmapClip = GetClipboardData (CF_BITMAP) ; if (hBitmapClip)
hBitmap = CopyBitmap (hBitmapClip) ; CloseClipboard () ;
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
}
break ; case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ; if (hBitmap)
{
GetClientRect (hwnd, &rect) ; hdcMem = CreateCompatibleDC (hdc) ;
SelectObject (hdcMem, hBitmap) ;
GetObject (hBitmap, sizeof (BITMAP), (PSTR) &bm) ;
SetStretchBltMode (hdc, COLORONCOLOR) ; StretchBlt (hdc, 0, 0, rect.right, rect.bottom,
hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY) ; DeleteDC (hdcMem) ;
}
EndPaint (hwnd, &ps) ;
return 0 ; case WM_DESTROY:
if (hBitmap)
DeleteObject (hBitmap) ; PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
以上代码摘自佩佐尔的programming windows第十四章的Blowup代码
使用方法:
在窗口中左键按下,不要放开
移动鼠标到窗口外,按下右键不动
拖拽鼠标,会看到矩形框,当放开左右键之一后,所选矩形框中的图像就画到的程序窗口中1.在获取所截取的矩形中的位图时即处理WM_RBUTTONUP或者WM_LBUTTONUP时候,为什么使用应用程序窗口来BLT位图?而不是锁定了的窗口hwndScr?
2.此程序在XP上时候,截取不到应用程序窗口左上角以左和以上的区域,为什么?
谢谢!
2.鼠标释放时的一句
StretchBlt (hdcMem, 0, 0, abs (ptEnd.x - ptBeg.x),
abs (ptEnd.y - ptBeg.y),
hdc, ptBeg.x, ptBeg.y, ptEnd.x - ptBeg.x,
ptEnd.y - ptBeg.y, SRCCOPY) ;这个ptEnd在左上角就会小于ptBeg.所以这个函数调用失败.
case WM_RBUTTONUP:
if (bBlocking)
{
InvertBlock (hwndScr, hwnd, ptBeg, ptEnd) ;
ptEnd.x = LOWORD (lParam) ;
ptEnd.y = HIWORD (lParam) ; if (hBitmap)
{
DeleteObject (hBitmap) ;
hBitmap = NULL ;
} hdc = GetDC (hwnd) ;//应该是hwndScr吧?
另外这些点的坐标全都要转换成屏幕坐标...
改成#3所说正确了。环境是WIN7 32另外,你坐标没偏移?这都不是屏幕坐标。
至于截取不到应用程序窗口左上角以左和以上的区域,是因为坐标值在lparam中本来有符号,但LOWORD,HIWORD两个宏只是简单地截取16位,左边补零。这对于LONG型的点坐标值来说将成为一个很大的正数,所以显示时总是直达右方和下方。要改的话把坐标值都转成short型就行了。
感觉是hdc = GetDC (hwnd) 这个hwnd取错了,应该取屏幕句柄或直接hdc=GetDC(NULL).
case WM_RBUTTONUP:
if (bBlocking)
{
InvertBlock (hwndScr, hwnd, ptBeg, ptEnd) ;
ptEnd.x = LOWORD (lParam) ;
ptEnd.y = HIWORD (lParam) ; if (hBitmap)
{
DeleteObject (hBitmap) ;
hBitmap = NULL ;
} hdc = GetDC (hwnd) ;//应该将此hwnd=NULL,这样在WIN7上才能正常工作
另外当鼠标到程序外面并且被捕捉后发送给程序的WM_LBUTTON等一系列消息的坐标就是屏幕坐标,因此不需要转换