Screenshot usando la API de ampliación: SetThreadDesktop falla cuando se alterna a un nuevo escritorio
Tengo el siguiente código delphi (reflejado enest C ++ ejemplo) capaz de tomar capturas de pantalla usandoMagnification
api ..
El código funciona bien cuando se captura el escritorio "predeterminado", pero también necesito capturar un nuevo escritorio activo y cuando alterno a un nuevo escritorio, el código falla en esta línea referente aSetThreadDesktop
:
if (not SetThreadDesktop(HNewDesk)) then
begin
Writeln('SetThreadDesktop Failed.');
Exit;
end;
Sé que no puedo llamar aSeThreadDesktop
dentro de un hilo que ya creó una ventana (en este caso, esta ventana parece ser referente aMagnification
API).
¿Cómo puedo resolver esto?
Aquí está el código completo:
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
Classes,
Graphics,
SysUtils,
Magnification;
var
MyBMP: TBitmap;
abitmap: HBitmap;
desktoprect: TRect;
hWndMag: HWND;
CallbackDone: Boolean;
function MagImageScalingCallback(HWND: HWND; srcdata: Pointer;
srcheader: MAGIMAGEHEADER; destdata: Pointer; destheader: MAGIMAGEHEADER;
unclipped: TRect; clipped: TRect; dirty: HRGN): BOOL; stdcall;
var
lpbmih: TBitmapInfoHeader;
lpbmi: TBitmapInfo;
ADC: HDC;
begin
ADC := GetWindowDC(HWND);
Fillchar(lpbmih, SizeOf(lpbmih), 0);
lpbmih.biSize := SizeOf(lpbmih);
lpbmih.biHeight := -srcheader.Height;
lpbmih.biWidth := srcheader.Width;
lpbmih.biSizeImage := srcheader.cbSize;
lpbmih.biPlanes := 1;
lpbmih.biBitCount := 32;
lpbmih.biCompression := BI_RGB;
Fillchar(lpbmi, SizeOf(lpbmi), 0);
lpbmi.bmiHeader.biSize := SizeOf(lpbmi.bmiHeader);
lpbmi.bmiHeader.biHeight := -srcheader.Height;
lpbmi.bmiHeader.biWidth := srcheader.Width;
lpbmi.bmiHeader.biSizeImage := srcheader.cbSize;
lpbmi.bmiHeader.biPlanes := 1;
lpbmi.bmiHeader.biBitCount := 32;
lpbmi.bmiHeader.biCompression := BI_RGB;
MyBMP := TBitmap.Create;
abitmap := 0;
try
abitmap := CreateDIBitmap(ADC, lpbmih, CBM_INIT, srcdata, lpbmi,
DIB_RGB_COLORS);
MyBMP.Handle := abitmap;
CallbackDone := True;
finally
DeleteDC(ADC);
end;
Result := True;
end;
function HostWndProc(hWindow: HWND; Msg: UINT; wParam: wParam; lParam: lParam)
: LRESULT; stdcall;
begin
Result := DefWindowProc(hWindow, Msg, wParam, lParam);
end;
procedure ConfigMag;
const
HOST_CLASSNAME = 'MagnifierHost';
var
wc: TWndClass;
hWndHost, desktop: HWND;
begin
hWndHost := 0;
wc.lpszClassName := HOST_CLASSNAME;
wc.lpfnWndProc := @HostWndProc;
wc.Style := 0;
wc.hInstance := 0;
wc.hIcon := 0;
wc.hCursor := 0;
wc.hbrBackground := 0;
wc.lpszMenuName := nil;
wc.cbClsExtra := 0;
wc.cbWndExtra := 0;
desktop := GetDesktopWindow;
GetWindowRect(desktop, desktoprect);
if (Windows.RegisterClass(wc) <> 0) then
hWndHost := CreateWindowEx(WS_EX_TOPMOST Or WS_EX_LAYERED or
WS_EX_TRANSPARENT, PChar(HOST_CLASSNAME), 'Host Window',
WS_POPUP or WS_CLIPCHILDREN, 0, 0, desktoprect.Width, desktoprect.Height,
0, 0, GetModuleHandle(0), nil);
if (hWndHost <> 0) then
begin
SetWindowPos(hWndHost, 0, 0, 0, desktoprect.Width, desktoprect.Height,
SWP_HIDEWINDOW);
SetLayeredWindowAttributes(hWndHost, 0, 255, LWA_ALPHA);
end;
If (MagInitialize) Then
hWndMag := CreateWindowEx(0, WC_MAGNIFIER, 'MagnifierWindow',
WS_CHILD or MS_SHOWMAGNIFIEDCURSOR or WS_VISIBLE, 0, 0, desktoprect.Width,
desktoprect.Height, hWndHost, 0, 0, nil);
If (hWndMag = 0) Then
Exit;
if (MagSetImageScalingCallback(hWndMag, MagImageScalingCallback)) then;
end;
procedure xGetScreenToBmp(index: Integer);
var
filterList: THWNDArray;
sourceRect: TRect;
begin
{ filterList[0] := Form1.Handle;
If (MagSetWindowFilterList(hWndMag, MW_FILTERMODE_EXCLUDE, 1,
@filterList[0])) Then; }
sourceRect.Left := 0;
sourceRect.Top := 0;
sourceRect.Right := desktoprect.Width;
sourceRect.Bottom := desktoprect.Height;
CallbackDone := False;
If (MagSetWindowSource(hWndMag, sourceRect)) Then;
repeat
Writeln('loop');
until CallbackDone;
MyBMP.PixelFormat := pf24bit;
MyBMP.SaveToFile('c:\capture\' + InttoStr(index) + '.bmp');
DeleteObject(abitmap);
MyBMP.Free;
end;
function SelectHDESK(HNewDesk: HDESK): Boolean; stdcall;
var
HOldDesk: HDESK;
dwDummy: DWORD;
sName: array [0 .. 255] of Char;
hThreadID: THandle;
ThreadID: DWORD;
begin
Result := False;
HOldDesk := GetThreadDesktop(GetCurrentThreadId);
if (not GetUserObjectInformation(HNewDesk, UOI_NAME, @sName[0], 256, dwDummy))
then
begin
Writeln('GetUserObjectInformation Failed.');
Exit;
end;
if (not SetThreadDesktop(HNewDesk)) then
begin
Writeln('SetThreadDesktop Failed.');
Exit;
end;
if (not CloseDesktop(HOldDesk)) then
begin
Writeln('CloseDesktop Failed.');
Exit;
end;
Result := True;
end;
function SelectDesktop(pName: PChar): Boolean; stdcall;
var
HDesktop: HDESK;
begin
Result := False;
if Assigned(pName) then
HDesktop := OpenDesktop(pName, 0, False, DESKTOP_CREATEMENU or
DESKTOP_CREATEWINDOW or DESKTOP_ENUMERATE or DESKTOP_HOOKCONTROL or
DESKTOP_WRITEOBJECTS or DESKTOP_READOBJECTS or DESKTOP_SWITCHDESKTOP or
GENERIC_WRITE)
else
HDesktop := OpenInputDesktop(0, False, DESKTOP_CREATEMENU or
DESKTOP_CREATEWINDOW or DESKTOP_ENUMERATE or DESKTOP_HOOKCONTROL or
DESKTOP_WRITEOBJECTS or DESKTOP_READOBJECTS or DESKTOP_SWITCHDESKTOP or
GENERIC_WRITE);
if (HDesktop = 0) then
begin
OutputDebugString(PChar('Get Desktop Failed: ' + InttoStr(GetLastError)));
Exit;
end;
Result := SelectHDESK(HDesktop);
end;
function InputDesktopSelected: Boolean; stdcall;
var
HThdDesk: HDESK;
HInpDesk: HDESK;
dwError: DWORD;
dwDummy: DWORD;
sThdName: array [0 .. 255] of Char;
sInpName: array [0 .. 255] of Char;
begin
Result := False;
HThdDesk := GetThreadDesktop(GetCurrentThreadId);
HInpDesk := OpenInputDesktop(0, False, DESKTOP_CREATEMENU or
DESKTOP_CREATEWINDOW or DESKTOP_ENUMERATE or DESKTOP_HOOKCONTROL or
DESKTOP_WRITEOBJECTS or DESKTOP_READOBJECTS or DESKTOP_SWITCHDESKTOP);
if (HInpDesk = 0) then
begin
Writeln('OpenInputDesktop Failed.');
dwError := GetLastError;
Result := (dwError = 170);
Exit;
end;
if (not GetUserObjectInformation(HThdDesk, UOI_NAME, @sThdName[0], 256,
dwDummy)) then
begin
Writeln('GetUserObjectInformation HThdDesk Failed.');
CloseDesktop(HInpDesk);
Exit;
end;
if (not GetUserObjectInformation(HInpDesk, UOI_NAME, @sInpName[0], 256,
dwDummy)) then
begin
Writeln('GetUserObjectInformation HInpDesk Failed.');
CloseDesktop(HInpDesk);
Exit;
end;
CloseDesktop(HInpDesk);
Result := (lstrcmp(sThdName, sInpName) = 0);
end;
var
idx: Integer;
begin
try
ConfigMag;
while True do
begin
if InputDesktopSelected then
xGetScreenToBmp(idx)
else if SelectDesktop(nil) then
xGetScreenToBmp(idx);
Sleep(3000);
Inc(idx);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Magnification.pas
unit Magnification;
{$ALIGN ON}
{$MINENUMSIZE 4}
interface
uses
Windows;
const
// Magnifier Class Name
WC_MAGNIFIERA: AnsiString = 'Magnifier';
WC_MAGNIFIERW: WideString = 'Magnifier';
WC_MAGNIFIER = 'Magnifier';
// Magnifier Window Styles
MS_SHOWMAGNIFIEDCURSOR = $0001;
MS_CLIPAROUNDCURSOR = $0002;
MS_INVERTCOLORS = $0004;
// Filter Modes
MW_FILTERMODE_EXCLUDE = 0;
MW_FILTERMODE_INCLUDE = 1;
type
tagMAGTRANSFORM = record
v: array[1..3, 1..3] of Single;
end;
MAGTRANSFORM = tagMAGTRANSFORM;
TMagTransform = tagMAGTRANSFORM;
PMagTransform = ^TMagTransform;
tagMAGIMAGEHEADER = record
width: UINT;
height: UINT;
format: TGUID;
stride: UINT;
offset: UINT;
cbSize: UINT;
end;
MAGIMAGEHEADER = tagMAGIMAGEHEADER;
TMagImageHeader = tagMAGIMAGEHEADER;
PMagImageHeader = ^TMagImageHeader;
tagMAGCOLOREFFECT = record
transform: array[1..5, 1..5] of Single;
end;
MAGCOLOREFFECT = tagMAGCOLOREFFECT;
TMagColorEffect = tagMAGCOLOREFFECT;
PMagColorEffect = ^TMagColorEffect;
TMagImageScalingCallback = function (hwnd: HWND; srcdata: Pointer;
srcheader: MAGIMAGEHEADER; destdata: Pointer; destheader: MAGIMAGEHEADER;
unclipped: TRect; clipped: TRect; dirty: HRGN): BOOL; stdcall;
THWNDArray = array[0..0] of HWND;
PHWNDArray = ^THWNDArray;
// Public Functions
function MagInitialize(): BOOL; stdcall;
function MagUninitialize(): BOOL; stdcall;
function MagSetWindowSource(hwnd: HWND; rect: TRect): BOOL; stdcall;
function MagGetWindowSource(hwnd: HWND; var Rect: TRect): BOOL; stdcall;
function MagSetWindowTransform(hwnd: HWND; var Transform: TMagTransform): BOOL; stdcall;
function MagGetWindowTransform(hwnd: HWND; var Transform: TMagTransform): BOOL; stdcall;
function MagSetWindowFilterList(hwnd: HWND; dwFilterMode: DWORD;
count: Integer; pHWND: PHWNDArray): BOOL; stdcall;
function MagGetWindowFilterList(hwnd: HWND; var dwFilterMode: DWORD;
count: Integer; pHWND: PHWNDArray): Integer; stdcall;
function MagSetImageScalingCallback(hwnd: HWND;
MagImageScalingCallback: TMagImageScalingCallback): BOOL; stdcall;
// MagImageScalingCallback WINAPI MagGetImageScalingCallback(HWND hwnd );
function MagSetColorEffect(hwnd: HWND; var Effect: TMagColorEffect): BOOL; stdcall;
function MagGetColorEffect(hwnd: HWND; var Effect: TMagColorEffect): BOOL; stdcall;
implementation
const
MagnificationDll = 'Magnification.dll';
function MagInitialize; external MagnificationDll name 'MagInitialize';
function MagUninitialize; external MagnificationDll name 'MagUninitialize';
function MagSetWindowSource; external MagnificationDll name 'MagSetWindowSource';
function MagGetWindowSource; external MagnificationDll name 'MagGetWindowSource';
function MagSetWindowTransform; external MagnificationDll name 'MagSetWindowTransform';
function MagGetWindowTransform; external MagnificationDll name 'MagGetWindowTransform';
function MagSetWindowFilterList; external MagnificationDll name 'MagSetWindowFilterList';
function MagGetWindowFilterList; external MagnificationDll name 'MagGetWindowFilterList';
function MagSetImageScalingCallback; external MagnificationDll name 'MagSetImageScalingCallback';
function MagSetColorEffect; external MagnificationDll name 'MagSetColorEffect';
function MagGetColorEffect; external MagnificationDll name 'MagGetColorEffect';
end.