Einzelnen Beitrag anzeigen

flashcoder

Registriert seit: 10. Nov 2013
83 Beiträge
 
#1

Wie mache ich einen screenshot in Z-Order mit PrintWindow-API?

  Alt 27. Apr 2019, 09:47
Delphi-Version: 10 Seattle
Ich versuche, einen C-Code zu übersetzen, der Screenshots in Z-Reihenfolge aufnehmen kann. Wenn ich den Delphi-Code teste, wird nur das Desktopfenster gedruckt. Wie kann das behoben werden?

C code:

Code:
#include "stdafx.h"
#include <Windows.h>
#include <gdiplus.h>
#include <conio.h>

#pragma warning(disable : 4996)

#pragma comment (lib,"Gdiplus.lib")

using namespace Gdiplus;

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT num = 0;
    UINT size = 0;

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL)
        return -1;

    GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j)
    {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }
    free(pImageCodecInfo);
    return -1;
}

//========================================================================================================

BOOL xPrintWindow(HWND hWnd, HDC hDc, HDC hDcScreen)
{
    BOOL ret = FALSE;
    RECT rect;
    GetWindowRect(hWnd, &rect);

    HDC    hDcWindow = CreateCompatibleDC(hDc);
    HBITMAP hBmpWindow = CreateCompatibleBitmap(hDc, rect.right - rect.left, rect.bottom - rect.top);

    SelectObject(hDcWindow, hBmpWindow);
    if (PrintWindow(hWnd, hDcWindow, 0))
    {
        BitBlt(hDcScreen,
            rect.left,
            rect.top,
            rect.right - rect.left,
            rect.bottom - rect.top,
            hDcWindow,
            0,
            0,
            SRCCOPY);

        ret = TRUE;
    }
    DeleteObject(hBmpWindow);
    DeleteDC(hDcWindow);
    return ret;
}

void EnumWindowsTopToDown(HWND owner, WNDENUMPROC proc, LPARAM param)
{
    HWND currentWindow = GetTopWindow(owner);
    if (currentWindow == NULL)
        return;
    if ((currentWindow = GetWindow(currentWindow, GW_HWNDLAST)) == NULL)
        return;
    while (proc(currentWindow, param) && (currentWindow = GetWindow(currentWindow, GW_HWNDPREV)) != NULL);
}

struct EnumHwndsPrintData
{
    HDC hDc;
    HDC hDcScreen;
};

BOOL CALLBACK EnumHwndsPrint(HWND hWnd, LPARAM lParam)
{
    EnumHwndsPrintData *data = (EnumHwndsPrintData *)lParam;

    if (!IsWindowVisible(hWnd))
        return TRUE;

    xPrintWindow(hWnd, data->hDc, data->hDcScreen);

    DWORD style = GetWindowLongA(hWnd, GWL_EXSTYLE);
    SetWindowLongA(hWnd, GWL_EXSTYLE, style | WS_EX_COMPOSITED);

    /*OSVERSIONINFOA versionInfo;
    ZeroMemory(&versionInfo, sizeof(OSVERSIONINFO));
    versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
    GetVersionExA(&versionInfo);

    if (versionInfo.dwMajorVersion < 6)
        EnumWindowsTopToDown(hWnd, EnumHwndsPrint, (LPARAM)data);*/

    return TRUE;
}

void testPrintWindow(int serverWidth, int serverHeight)
{

    RECT rect;
    HWND hWndDesktop = GetDesktopWindow();
    GetWindowRect(hWndDesktop, &rect);

    HDC    hDc = GetDC(NULL);
    HDC    hDcScreen = CreateCompatibleDC(hDc);
    HBITMAP hBmpScreen = CreateCompatibleBitmap(hDc, rect.right, rect.bottom);
    SelectObject(hDcScreen, hBmpScreen);

    EnumHwndsPrintData data;
    data.hDc = hDc;
    data.hDcScreen = hDcScreen;

    EnumWindowsTopToDown(NULL, EnumHwndsPrint, (LPARAM)&data);

    if (serverWidth > rect.right)
        serverWidth = rect.right;
    if (serverHeight > rect.bottom)
        serverHeight = rect.bottom;

    if (serverWidth != rect.right || serverHeight != rect.bottom)
    {
        HBITMAP hBmpScreenResized = CreateCompatibleBitmap(hDc, serverWidth, serverHeight);
        HDC    hDcScreenResized = CreateCompatibleDC(hDc);

        SelectObject(hDcScreenResized, hBmpScreenResized);
        SetStretchBltMode(hDcScreenResized, HALFTONE);
        StretchBlt(hDcScreenResized, 0, 0, serverWidth, serverHeight,
            hDcScreen, 0, 0, rect.right, rect.bottom, SRCCOPY);

        DeleteObject(hBmpScreen);
        DeleteDC(hDcScreen);

        hBmpScreen = hBmpScreenResized;
        hDcScreen = hDcScreenResized;
    }

//=======================================================================================================

    // ========== HBITMAP to bmp file ===========

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    Bitmap *image = new Bitmap(hBmpScreen, NULL);

    CLSID myClsId;
    int retVal = GetEncoderClsid(L"image/bmp", &myClsId);

    image->Save(L"output.bmp", &myClsId, NULL);
    delete image;

    GdiplusShutdown(gdiplusToken);

    //=======================================================================

}

int _tmain(int argc, _TCHAR* argv[])
{
    testPrintWindow(800, 600);

    _getch();

    return 0;
}
Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Windows,
  Vcl.Graphics,
  SysUtils;

type
  PEnumHwndsPrintData = ^TEnumHwndsPrintData;

  TEnumHwndsPrintData = record
    _hDc: HDC;
    hDcScreen: HDC;
  end;

type
  TFNWndEnumProc = function(_hwnd: HWND; _lParam: LPARAM): BOOL; stdcall;

function xPrintWindow(_hwnd: HWND; _hDc, hDcScreen: HDC): BOOL;
const
  sPrintWindow = 'PrintWindow';
var
  PrintWindowAPI: function(sourceHandle: HWND; destinationHandle: HDC;
    nFlags: UINT): BOOL; stdcall;
  User32DLLHandle: THandle;
  bPrint: Boolean;
  Ret: BOOL;
  R: TRect;
  hDcWindow: HDC;
  hBmpWindow: HBITMAP;
begin
  Ret := False;

  User32DLLHandle := GetModuleHandle(user32);
  if User32DLLHandle <> 0 then
  begin
    @PrintWindowAPI := GetProcAddress(User32DLLHandle, sPrintWindow);

    if @PrintWindowAPI <> nil then
    begin
      GetWindowRect(_hwnd, R);

      hDcWindow := CreateCompatibleDC(_hDc);
      hBmpWindow := CreateCompatibleBitmap(_hDc, R.Right - R.Left,
        R.Bottom - R.Top);

      SelectObject(hDcWindow, hBmpWindow);

      bPrint := PrintWindowAPI(_hwnd, hDcWindow, 0);

      if bPrint then
      begin
        BitBlt(hDcScreen, R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
          hDcWindow, 0, 0, SRCCOPY);

        Ret := True;
      end;
      DeleteObject(hBmpWindow);
      DeleteDC(hDcWindow);
    end;
  end;
  Result := Ret;
end;

function GetPrevHwnd(hWindow: HWND): HWND;
begin
  hWindow := GetWindow(hWindow, GW_HWNDPREV);
  Result := hWindow;
end;

procedure EnumWindowsTopToDown(Owner: HWND; Proc: TFNWndEnumProc;
  _Param: LPARAM);
var
  CurrentWindow, _CurrentWindow: HWND;
begin
  repeat
    CurrentWindow := GetTopWindow(Owner);
    if CurrentWindow = 0 then
      Exit;

    CurrentWindow := GetWindow(CurrentWindow, GW_HWNDLAST);
    if CurrentWindow = 0 then
      Exit;

    _CurrentWindow := GetPrevHwnd(CurrentWindow);

  until Proc(CurrentWindow, _Param) and (_CurrentWindow <> 0);
end;

function EnumHwndsPrint(wHandle: HWND; _lParam: LPARAM): BOOL; stdcall;
var
  VersionInfo: TOSVersionInfo;
  Data: PEnumHwndsPrintData;
  Style: DWORD;
begin
  Result := True;

  if not IsWindowVisible(wHandle) then
    Exit;

  Data := PEnumHwndsPrintData(_lParam);
  Writeln('oi');
  xPrintWindow(wHandle, Data._hDc, Data.hDcScreen);

  Style := GetWindowLong(wHandle, GWL_EXSTYLE);
  SetWindowLong(wHandle, GWL_EXSTYLE, Style or WS_EX_COMPOSITED);

  VersionInfo.dwOSVersionInfoSize := SizeOf(VersionInfo);
  GetVersionEx(VersionInfo);

  if (VersionInfo.dwMajorVersion < 6) then
    EnumWindowsTopToDown(wHandle, EnumHwndsPrint, LPARAM(Data));
end;

procedure testPrintWindow(Width, Height: Integer);
var
  hWndDesktop: HWND;
  Data: TEnumHwndsPrintData;
  _hDcScreen, hDc_, hDcScreenResized: HDC;
  hBmpScreen, hBmpScreenResized: HBITMAP;
  Rect: TRect;
  bmp: TBitmap;
begin
  hWndDesktop := GetDesktopWindow;
  GetWindowRect(hWndDesktop, Rect);

  hDc_ := GetDC(0);
  _hDcScreen := CreateCompatibleDC(hDc_);
  hBmpScreen := CreateCompatibleBitmap(hDc_, Rect.Right, Rect.Bottom);

  SelectObject(_hDcScreen, hBmpScreen);

  with Data do
  begin
    _hDc := hDc_;
    hDcScreen := _hDcScreen;
  end;

  EnumWindowsTopToDown(0, EnumHwndsPrint, LPARAM(@Data));

  if (Width > Rect.Right) then
    Width := Rect.Right;

  if (Height > Rect.Bottom) then
    Height := Rect.Bottom;

  if (Width <> Rect.Right) or (Height <> Rect.Bottom) then
  begin
    hBmpScreenResized := CreateCompatibleBitmap(hDc_, Width, Height);

    hDcScreenResized := CreateCompatibleDC(hDc_);

    SelectObject(hDcScreenResized, hBmpScreenResized);

    SetStretchBltMode(hDcScreenResized, HALFTONE);

    StretchBlt(hDcScreenResized, 0, 0, Width, Height, _hDcScreen, 0, 0,
      Rect.Right, Rect.Bottom, SRCCOPY);

    DeleteObject(hBmpScreen);
    DeleteDC(_hDcScreen);

    hBmpScreen := hBmpScreenResized;
    _hDcScreen := hDcScreenResized;
  end;

  bmp := TBitmap.Create;
  bmp.Handle := hBmpScreen;
  bmp.SaveToFile('output.bmp');
  bmp.Free;
end;

begin
  try
    testPrintWindow(800, 600);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.

Geändert von flashcoder (27. Apr 2019 um 09:54 Uhr)
  Mit Zitat antworten Zitat