Bildschirmlupe soll mein Fenster nicht mitanzeigen... BitBlt,StretchBlt



  • Moin!

    Ich bin dabei, eine Bildschirmlupe zu programmieren (als kleinen Einstieg in die WinAPI-Programmierung), habe jedoch das Problem, dass mein Fenster, die Lupe selbst, ja auch ChildWindow des Desktop ist und mit angezeigt wird. Dies ist natürlich nicht erwünscht.

    Wie kann ich das hinbekommen? Ich habe schon versucht, die ZOrdner kurzzeitig zu ändern oder per ShowWindow() mein Fenster zu verstecken, bis die Bilddaten gespeichert sind. Aber beides resultiert darin, dass das Fenster ständig den Fokus verliert/bekommt.

    Ich hoffe, jemand hat einen besseren Vorschlag. Ansonsten funktioniert alles.

    Hier der komplette Code. Irrelevante Funktionen wie z.B. CenterWindow() bitte ignorieren, interessant ist eigentlich nur ScreenShotDesktop().

    #include "windows.h"
    #include "assert.h"
    #include "PowrProf.h"
    #include "malloc.h"
    #include <wingdi.h>
    #include <winbase.h>
    #include <stdio.h>
    
    LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
    
    unsigned long CalculateSpeed();
    int CenterWindow(HWND hWnd);
    
    BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam);
    HRGN CopyRgn(HRGN hRgnSrc);
    void ScreenShotDesktop(HDC *hDC);
    
    const char szAppName[] = "myWin32TestApp";
    
    const UINT TimerSec = 1;
    UINT WinPosX;
    UINT WinPosY;
    const UINT WinSizeX = 500;
    const UINT WinSizeY = 300;
    
    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,sMhz,WS_OVERLAPPED|WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,WinSizeX,WinSizeY,NULL,NULL,hInstance,NULL);
      //
      ShowWindow(hWnd,iCmdShow);  //Fenster anzeigen
      CenterWindow(hWnd);
      UpdateWindow(hWnd);   //sendet WM_PAINT, um die Anzeige zu aktualisieren
      //
      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) {
          MessageBox(NULL,"GetMessage()==-1",NULL,MB_OK);
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      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:
          return 0;
        case WM_SIZE:
        {
          rect.right =  LOWORD(lParam);
          rect.bottom = HIWORD(lParam);
          return 0;
        }
        case WM_KEYDOWN:
          switch(wParam) {
            case VK_ESCAPE:
              SendMessage(hWnd,WM_CLOSE,0,0);
              return 0;
          }  
          return 0;
        case WM_MOVE:
          {
            WinPosX = (int)(short) LOWORD(lParam);    // horizontal position 
            WinPosY = (int)(short) HIWORD(lParam);    // vertical position 
            //        
            InvalidateRgn(hWnd,NULL,false);
            //UpdateWindow(hWnd);
            return 0;
          }
        case WM_PAINT:
          {
            PAINTSTRUCT ps;
            HDC hDC;
            COLORREF crfPixel;
            HWND    hWndDesktop = GetDesktopWindow();
            HDC     hdcDesktop  = GetDC(NULL/*hWndDesktop*/);
            hDC = BeginPaint(hWnd,&ps);
            //
            ScreenShotDesktop(&hDC);
            EndPaint(hWnd,&ps);
            return 0;
          }
        case WM_DESTROY:
          if(isActive) {
            KillTimer(hWnd,TimerSec);
          }
          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) {
    //--------------------------------------------------------------------------------------------------------------------------
      int     nWidth  = GetSystemMetrics(SM_CXSCREEN);
      int     nHeight = GetSystemMetrics(SM_CYSCREEN);
      //  
      RECT rcWinPos;
      GetWindowRect(hWnd,&rcWinPos);
      //
      HWND    hWndDesktop = ::GetDesktopWindow();
      HDC     hdc     = ::GetDC(hWndDesktop);
      HDC     memDC   = ::CreateCompatibleDC(hdc);
      HBITMAP hbm     = ::CreateCompatibleBitmap(hdc, nWidth, nHeight);
      HBITMAP hbmOld  = (HBITMAP)::SelectObject(memDC, hbm);
      //
      ::BitBlt(memDC,0,0,WinSizeX,WinSizeY,hdc,WinPosX-100/*rcWinPos.left-200*/,WinPosY-100/*rcWinPos.top-200*/,SRCCOPY);
      //::BitBlt(memDC, rcWinPos.top ,rcWinPos.left ,rcWinPos.top+ WinSizeX ,rcWinPos.left+ WinSizeY, hdc, 0, 0, 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);
      //
      delete[] pbBits;
    }
    


  • Hat denn keiner eine Idee?

    Ich weiß, dass die Benutzerkontensteuerung (UAC) in WinVista beim Anlegen eines Screenshots nicht auf diesem zu sehen ist (habe ich in irgendeiner Zeitschrift gelesen). Daher muss die UAC ja irgendwie vom Desktop losgelöst sein, also z.B. auf einem anderen Desktop oder Layer oder sonst-irgendwas liegen.

    Könnte das der richtige Lösungsansatz sein? Falls dem so ist, müsste ich die Lupe auf dem zweiten Desktop erzeugen, mir den Bildspeicher aber vom ersten Desktop holen. Der zweite müsste dann ein Abbild des Haupt-Desktops sein. Gibt es da eine Möglichkeit, so etwas wie ein DuplicateDesktop() oder so? In der MSDN finde ich nichts passendes.

    Gruß Matze



  • Ich würde die Funktion ScreenShotDesktop auch nicht im WM_PAINT aufrufen. Wenn du dein Fenster versteckst und dann wieder herstellst, wird beim Herstellen natürlich wieder ein WM_PAINT ausgelöst. Dieses ruft wiederum die Funktion auf und du hast in dem Fall auch wahrscheinlich wieder dein Fenster mit auf dem Screenshot.



  • Ich denke, die Sache mit Fenster verstecken und wieder anzeigen lassen kann ich vergessen. Das müsste ja bei jeder Bewegung des Fensters passieren...

    Mal 'ne andere Frage (auch für dieses Projekt): Kann ich bzw. wie kann ich mein Fenster im Vollbildmodus ohne DirectX/OpenGL darstellen lassen? Das muss doch möglich sein, oder?

    Ich habe folgendes versucht:

    void DisplayBitmapFullscreen(void) {
      DEVMODE dmScreenSettings;
      if(EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dmScreenSettings)==0) {
        MessageBox(NULL,"FullScreen klappt net...",NULL,MB_OK);
      }
    
      memset(&dmScreenSettings,0,sizeof(dmScreenSettings));    // Makes Sure Memory's Cleared 
      dmScreenSettings.dmSize=sizeof(dmScreenSettings);        // Size Of The Devmode Structure 
      dmScreenSettings.dmPelsWidth    = GetSystemMetrics(SM_CXSCREEN);    // Selected Screen Width 
      dmScreenSettings.dmPelsHeight    = GetSystemMetrics(SM_CXSCREEN);   // Selected Screen Height 
      dmScreenSettings.dmBitsPerPel    = 16;                    // Selected Bits Per Pixel 
      dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
    
      if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) {
        MessageBox(NULL,"FullScreen klappt net... ChangeDisplaySettings()...",NULL,MB_OK);
      }
    
      return;
    }
    

    Jedoch meldet ChangeDisplaySettings() immer einen Fehler (DISP_CHANGE_BADMODE).

    Gruß Matze



  • _matze schrieb:

    Ich denke, die Sache mit Fenster verstecken und wieder anzeigen lassen kann ich vergessen. Das müsste ja bei jeder Bewegung des Fensters passieren...

    War auch nur als Hinweis, dass eben beim Wiederherstellen des Fensters WM_PAINT aufgerufen wird.

    _matze schrieb:

    Mal 'ne andere Frage (auch für dieses Projekt): Kann ich bzw. wie kann ich mein Fenster im Vollbildmodus ohne DirectX/OpenGL darstellen lassen? Das muss doch möglich sein, oder?

    Wenn ich das richtig verstanden habe, schau mal hier



  • 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));
    }
    

Anmelden zum Antworten