I'm trying translate a C code that is able of take screenshot in Z-Order but after translate this code practically equals to original (C), on Win 7 i'm getting black screenshot, on Win 10 only desktop is printed. How fix this?
Here is the C code:
Here is the C code:
Code: Select all
And here is my translation to Delphi:#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;
}
//=======================================================================================================
// ========== Here is restrict to C++ to save HBITMAP to 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;
}
Code: Select all
unit Unit1;
//...
type
PEnumHwndsPrintData = ^TEnumHwndsPrintData;
TEnumHwndsPrintData = record
_hDc: HDC;
hDcScreen: HDC;
end;
type
TFNWndEnumProc = function(_hwnd: HWND; _lParam: LPARAM): BOOL; stdcall;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
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);
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;
procedure TForm4.Button1Click(Sender: TObject);
begin
testPrintWindow(800, 600);
end;
end.