_
Moin!
Erstmal danke an Analog Bit für die Tipps. Der Link für die Vollbild-Anzeige klappt super. Letztendlich hat sich jedoch herausgestellt, dass ich erstmal doch kein Vollbild brauche.
Die Lupe funktioniert mittlerweile ganz gut, und zwar wird beim Programmstart ein Screenshot des Desktops erzeugt. Aus diesem Grafikspeicher wird dann der zu vergrößernde Bereich in der Lupe dargestellt.
Zoomen kann man mit dem Mausrad, die Mausrad-Taste stellt wieder die Standard-Vergrößerung (2X) ein, linke und rechte Taste beenden das Programm. Ich plane noch die Möglichkeit, die Größe der Lupe verändern zu können.
Das einzige Problem bei der Geschichte ist folgendes: Die Lupe hängt am Mauscursor, so dass es nicht so ganz einfach ist, den Fokus an ein anderes Fenster zu verlieren. Wenn der Benutzer es trotzdem schafft, den Fokus zu wechseln und so den Desktop zu verändern (z.B. Maximieren irgendeines Fensters durch Alt+TAB, Task-Manager, Klick auf die Taskleiste, etc.), so ist der Inhalt der Lupe (Screenshot) nicht mehr passend zum Desktop. Da wäre vielleicht doch ein Vollbild-Fenster, dass den erstellten Screenshot anzeigt, ratsam.
Zudem kommt der Mauscursor hin und wieder doch zutage, obwohl eigentlich durch SetCursor() versteckt. So muss ich ihn in jeder WM_MOUSEMOVE wieder von neuem verstecken. Wer einen Tipp hat, welche Funktion dafür sorgt, dass der Cursor plötzlich wieder gezeigt wird, her damit!
Wer das Programm mal ausprobieren möchte, hier gibt's nochmal den kompletten, aktuellen Code:
Kritik und Anregungen sind natürlich erwünscht.
Gruß Matze
#define _WIN32_WINNT 0x0401
#define _WIN32_WINDOWS 0x04001
#include "windows.h"
#include "assert.h"
#include "PowrProf.h"
#include "malloc.h"
#include <wingdi.h>
#include <winbase.h>
#include <stdio.h>
#include "ddraw.h"
#include "winuser.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
unsigned long CalculateSpeed();
int CenterWindow(HWND hWnd);
void restoreCursor(void);
void hideCursor(void);
BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam);
HRGN CopyRgn(HRGN hRgnSrc);
void ScreenShotDesktop(HDC *hDC);
void ScreenShotWholeDesktop();
//
const char szAppName[] = "myWin32TestApp";
const char szFullScreenName[] = "FullScreenWin";
const UINT TimerSec = 1;
//
UINT WinPosX;
UINT WinPosY;
UINT WinSizeX = 480;
UINT WinSizeY = 360;
//
double iLupeFaktor=2;
//
HBITMAP hbm;
HBITMAP hbmOld;
//
HWND hWnd; //Fenster-Handle
//--------------------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow) {
//--------------------------------------------------------------------------------------------------------------------------
MSG msg; //Struktur für Windows-Nachrichten
WNDCLASS wc; //Struktur für den Typ der Fensterklasse
//
int iGetMessageRetVal;
//
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc; //Adresse der Funktion, die die Nachrichtenbehandlung übernehmen soll (Callback-Funktion)
wc.cbClsExtra = 0; //zusätzlichen Speicher kann mit diesen Variablen
wc.cbWndExtra = 0; //für das Fenster reserviert werden (?)
wc.lpszClassName = szAppName; //Fensterklassenname, hierüber kann man dann Instanzen der Fensterklasse erzeugen
wc.lpszMenuName = NULL;
wc.hInstance = hInstance; //Handle der Programminstanz
wc.hCursor = LoadCursor(NULL,IDC_ARROW); //zu verwendender Cursor
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); //zu verwendendes Icon
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
//
RegisterClass(&wc); //die Fensterklasse muss registriert werden, um in CreateWindow() benutzt werden zu können
//
/*
char sMhz[10];
wsprintf(sMhz,"%i MHz",CalculateSpeed());
*/
//
hWnd = CreateWindow(szAppName,"Lupe",WS_OVERLAPPED,CW_USEDEFAULT,CW_USEDEFAULT,WinSizeX,WinSizeY,NULL,NULL,hInstance,NULL);
//
ScreenShotWholeDesktop();
hbm = (HBITMAP)LoadImage( NULL,
"__TMP__SCRNSHOT__2357__.BMP",
IMAGE_BITMAP,
0,
0,
LR_LOADFROMFILE );
//
ShowWindow(hWnd,iCmdShow);
CenterWindow(hWnd);
UpdateWindow(hWnd);
//
while(iGetMessageRetVal=GetMessage(&msg,NULL,0,0)) { //2. Parameter muss NULL sein, sonst richten sich die Nachrichten nur an den Thread, nicht ans Fenster
if(iGetMessageRetVal==-1) { break; }
TranslateMessage(&msg);
DispatchMessage(&msg);
//
}
//
DeleteObject(hbm); //ScreenShot-Objekt
DeleteObject(hbmOld);
//
return msg.wParam;
}
//--------------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
//--------------------------------------------------------------------------------------------------------------------------
static RECT rect;
static bool isActive;
//
switch(msg) {
case WM_CREATE:
SetCursorPos(GetSystemMetrics(SM_CXSCREEN)/2,GetSystemMetrics(SM_CYSCREEN)/2);
hideCursor();
return 0;
case WM_SIZE:
{
rect.right = LOWORD(lParam);
rect.bottom = HIWORD(lParam);
return 0;
}
case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN: //warum klappt das nicht? Nur MK_LBUTTON geht...
SendMessage(hWnd,WM_CLOSE,0,0);
return 0;
case WM_MBUTTONDOWN:
iLupeFaktor=2;
InvalidateRgn(hWnd,NULL,false);
return 0;
case WM_KEYDOWN:
switch(wParam) {
case VK_SPACE:
case VK_ESCAPE:
SendMessage(hWnd,WM_CLOSE,0,0);
return 0;
}
return 0;
case WM_MOUSEMOVE:
{
POINT pn;
//
GetCursorPos(&pn);
SetWindowPos(hWnd,HWND_TOP,pn.x-(WinSizeX/2),pn.y-(WinSizeY/2),0,0,SWP_NOSIZE|SWP_NOZORDER);
hideCursor();
InvalidateRgn(hWnd,NULL,false);
return 0;
}
case WM_MOUSEWHEEL:
{
long fwKeys = LOWORD(wParam); // key flags
long zDelta = (short) HIWORD(wParam); // wheel rotation
long xPos = (short) LOWORD(lParam); // horizontal position of pointer
long yPos = (short) HIWORD(lParam); // vertical position of pointer
if(zDelta>0) {
iLupeFaktor+=.5;
}
if(zDelta<0) {
iLupeFaktor-=.5;
}
if(iLupeFaktor<=1) {
iLupeFaktor=1;
}
InvalidateRgn(hWnd,NULL,false);
return 0;
}
case WM_MOVE:
{
WinPosX = (int)(short) LOWORD(lParam); // horizontal position
WinPosY = (int)(short) HIWORD(lParam); // vertical position
//
InvalidateRgn(hWnd,NULL,false);
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// HDC hDC=GetDC(hWnd);
/*
hbm = (HBITMAP)LoadImage( NULL,
"__TMP__SCRNSHOT__2357__.BMP",
IMAGE_BITMAP,
0,
0,
LR_LOADFROMFILE );
*/
HDC hdcMem = CreateCompatibleDC(hdc);
hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
BITMAP bm;
GetObject(hbm,sizeof(bm),&bm);
//BitBlt(hdc,0,0,WinSizeX,WinSizeY,hdcMem,WinPosX,WinPosY,SRCCOPY);
StretchBlt(hdc,
0,
0,
WinSizeX,
WinSizeY,
hdcMem,
WinPosX+( ((double)WinSizeX/2.0)-((double)WinSizeX/iLupeFaktor/2.0) ),
WinPosY+( ((double)WinSizeY/2.0)-((double)WinSizeY/iLupeFaktor/2.0) ),
(int)((double)WinSizeX/iLupeFaktor),
(int)((double)WinSizeY/iLupeFaktor),
SRCCOPY);
//
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
//DeleteObject(hbm);
//DeleteObject(hbmOld);
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
restoreCursor();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
//--------------------------------------------------------------------------------------------------------------------------
unsigned long CalculateSpeed() {
//--------------------------------------------------------------------------------------------------------------------------
unsigned int nStartLow, nStartHigh;
unsigned int nEndLow, nEndHigh;
unsigned long nStart = 0, nEnd = 0;
#if defined(_MSC_VER)
_asm
{
rdtsc
mov [nStartLow], eax
mov [nStartHigh], edx
}
#else
asm volatile("rdtsc" : "=a"(nStartLow), "=d"(nStartHigh));
#endif
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
#if defined(_MSC_VER)
_asm
{
rdtsc
mov [nEndLow], eax
mov [nEndHigh], edx
}
#else
asm volatile("rdtsc" : "=a"(nEndLow), "=d"(nEndHigh));
#endif
nStart |= nStartHigh;
nStart <<= 32;
nStart |= nStartLow;
nEnd |= nEndHigh;
nEnd <<= 32;
nEnd |= nEndLow;
return(static_cast<unsigned long>(((nEnd - nStart) / 1) / 1000000));
}
//--------------------------------------------------------------------------------------------------------------------------
int CenterWindow(HWND hWnd)
//--------------------------------------------------------------------------------------------------------------------------
{
if(!IsWindow(hWnd))
{
SetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
HWND hWndParent;
RECT rc, rcParent;
if(NULL != (hWndParent = GetParent(hWnd))) // Gibt es Parent?
{
GetClientRect(hWndParent, &rcParent);
}
else if(NULL != (hWndParent = GetWindow(hWnd, GW_OWNER))) // Gibt es einen Owner?
{
GetWindowRect(hWndParent, &rcParent);
}
else
{
SetRectEmpty(&rcParent);
if(IsRectEmpty(&rcParent))
{
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcParent, 0);
}
}
GetWindowRect(hWnd, &rc);
int x = (((rcParent.right - rcParent.left) - (rc.right - rc.left)) / 2) +
rcParent.left;
int y = (((rcParent.bottom - rcParent.top) - (rc.bottom - rc.top)) / 2) +
rcParent.top;
return(SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOOWNERZORDER |
SWP_NOSENDCHANGING | SWP_NOSIZE |
SWP_NOZORDER));
}
//--------------------------------------------------------------------------------------------------------------------------
HRGN CopyRgn(HRGN hRgnSrc)
//--------------------------------------------------------------------------------------------------------------------------
{
DWORD dwCount = GetRegionData(hRgnSrc, 0, NULL);
if(!dwCount)
return(NULL);
RGNDATA* pData = reinterpret_cast<RGNDATA*>(_alloca(dwCount));
GetRegionData(hRgnSrc, dwCount, pData);
return(ExtCreateRegion(NULL, dwCount, pData));
}
// Die EnumProc fuegt die Child-Windows nun endlich der in der WndProc
// erstellten Region hinzu. Die Region kommt ueber lParam in der EnumProc an.
//--------------------------------------------------------------------------------------------------------------------------
BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam)
//--------------------------------------------------------------------------------------------------------------------------
{
HWND hWndParent = GetParent(hWnd);
HRGN hRgn1, hRgn2, hRgn;
RECT rc, rcParent;
GetWindowRect(hWndParent, &rcParent);
GetWindowRect(hWnd, &rc);
rc.right -= rc.left;
rc.bottom -= rc.top;
rc.left -= rcParent.left;
rc.top -= rcParent.top;
rc.right += rc.left;
rc.bottom += rc.top;
hRgn = reinterpret_cast<HRGN>(lParam);
hRgn1 = CopyRgn(hRgn);
hRgn2 = CreateRectRgnIndirect(&rc);
CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR);
DeleteObject(hRgn1);
DeleteObject(hRgn2);
return(TRUE);
}
//--------------------------------------------------------------------------------------------------------------------------
void ScreenShotDesktop(HDC *hDC) { //wird momentan NICHT benutzt
//--------------------------------------------------------------------------------------------------------------------------
int nWidth = GetSystemMetrics(SM_CXSCREEN);
int nHeight = GetSystemMetrics(SM_CYSCREEN);
//
RECT rcWinPos;
GetWindowRect(hWnd,&rcWinPos);
//
HWND hWndDesktop = ::GetDesktopWindow();
HDC hdc = ::GetDC(hWnd);
HDC memDC = ::CreateCompatibleDC(hdc);
HBITMAP hbm = ::CreateCompatibleBitmap(hdc, nWidth, nHeight);
//
HBITMAP hbmOld = (HBITMAP)LoadImage(NULL,"__TMP__SCRNSHOT__2357__.BMP",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
//
::BitBlt(memDC,0,0,WinSizeX,WinSizeY,hdc,WinPosX-80/*rcWinPos.left-200*/,WinPosY-80/*rcWinPos.top-200*/,SRCCOPY);
//
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(bmi));
//
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = WinSizeX;
bmi.bmiHeader.biHeight = WinSizeY;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 32 * WinSizeX * WinSizeY / 8;
//
BYTE *pbBits = new BYTE[bmi.bmiHeader.biSizeImage];
//
::GetDIBits( memDC,hbm,0,bmi.bmiHeader.biHeight,pbBits,&bmi,DIB_RGB_COLORS );
//
BITMAPFILEHEADER bfh;
bfh.bfType = ('M' << 8) + 'B';
bfh.bfSize = sizeof(BITMAPFILEHEADER) +
bmi.bmiHeader.biSizeImage +
sizeof(BITMAPINFOHEADER);
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//
SetDIBits(memDC,hbm,0,bmi.bmiHeader.biHeight,pbBits,&bmi,DIB_RGB_COLORS);
//BitBlt (*hDC, 0, 0, WinSizeX,WinSizeY,memDC, 0, 0, SRCCOPY);
StretchBlt(*hDC, 0, 0, WinSizeX,WinSizeY,memDC, 0, 0,WinSizeX/2,WinSizeY/2,SRCCOPY);
//
::SelectObject(memDC, hbmOld);
::DeleteDC(memDC);
::ReleaseDC(hWndDesktop,hdc);
::DeleteObject(hbm);
::DeleteObject(hbmOld);
//
delete[] pbBits;
}
//--------------------------------------------------------------------------------------------------------------------------
void ScreenShotWholeDesktop() {
//--------------------------------------------------------------------------------------------------------------------------
int nWidth = GetSystemMetrics(SM_CXSCREEN);
int nHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hWnd = ::GetDesktopWindow();
HDC hdc = ::GetDC(hWnd);
HDC memDC = ::CreateCompatibleDC(hdc);
HBITMAP hbm = ::CreateCompatibleBitmap(hdc, nWidth, nHeight);
HBITMAP hbmOld = (HBITMAP)::SelectObject(memDC, hbm);
::BitBlt(memDC, 0, 0, nWidth, nHeight, hdc, 0, 0, SRCCOPY);
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = nWidth;
bmi.bmiHeader.biHeight = nHeight;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 32 * nWidth * nHeight / 8;
BYTE *pbBits = new BYTE[bmi.bmiHeader.biSizeImage];
::GetDIBits( memDC,
hbm,
0,
bmi.bmiHeader.biHeight,
pbBits,
&bmi,
DIB_RGB_COLORS );
BITMAPFILEHEADER bfh;
bfh.bfType = ('M' << 8) + 'B';
bfh.bfSize = sizeof(BITMAPFILEHEADER) +
bmi.bmiHeader.biSizeImage +
sizeof(BITMAPINFOHEADER);
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
SetDIBits(memDC,hbm,0,bmi.bmiHeader.biHeight,pbBits,&bmi,DIB_RGB_COLORS);
// StretchBlt(*hDC, 0, 0, WinSizeX,WinSizeY,memDC, 0, 0,WinSizeX/2,WinSizeY/2,SRCCOPY);
// BitBlt(*hDC, 0, 0, GetSystemMetrics(SM_CXSCREEN)-1,GetSystemMetrics(SM_CYSCREEN)-1,memDC, 0, 0, SRCCOPY);
HANDLE hfile = CreateFile( "__TMP__SCRNSHOT__2357__.BMP",
GENERIC_WRITE,
0,
0,
OPEN_ALWAYS,
0,
0 );
DWORD dwWritten;
WriteFile(hfile,&bfh, sizeof(bfh), &dwWritten, NULL);
WriteFile(hfile,&bmi.bmiHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
WriteFile(hfile,pbBits, bmi.bmiHeader.biSizeImage, &dwWritten, NULL);
CloseHandle(hfile);
::SelectObject(memDC, hbmOld);
::DeleteDC(memDC);
::ReleaseDC(hWnd,hdc);
::DeleteObject(hbm);
delete[] pbBits;
}
//--------------------------------------------------------------------------------------------------------------------------
void hideCursor(void) {
//--------------------------------------------------------------------------------------------------------------------------
SetCursor(NULL);
}
//--------------------------------------------------------------------------------------------------------------------------
void restoreCursor(void) {
//--------------------------------------------------------------------------------------------------------------------------
SetCursor(LoadCursor(NULL,IDC_ARROW));
}