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.