windowsdelphiwinapiscreensavermirroring

How can I start screensaver in its own Window (Form,canvas) in Delphi?


I use software that mirrors my PC to the TV. Works well, but the transfer crashes when transferring screensavers.

One of the screensavers offers the option to start it in its own window - so the mirroring works perfectly. So I'm looking for a way to start the screensaver in its own window (a Form, for example) and then transfer it to the television.

Unfortunately, the first attempt doesn't work; I probably don't get the right handle to the screensaver. Starting with the "/P" parameter didn't work, either.

Can someone help me? The OS is "Windows 11".

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
   Shift: TShiftState);
var
   hMyApp: hwnd; //Handle auf das Window welches man im Form braucht
   vWinHnd: hwnd;
   VExePfad: string;
   vParam: string;
begin
   if Key = ord(32) then
   begin
      try
         vWinHnd := Form1.Handle;
         vParam := '/P ' + inttostr(vWinHnd) ;
         vExePfad := 'C:\Windows\System32\Bubbles.scr';
         ShellExecute(0,
            nil,
            PChar(vExePfad),
            //PChar(vParam),
            nil,
            nil,
            SW_MINIMIZE );
            application.ProcessMessages;
         hMyApp := GetwindowDc(0);
         form1.Caption := 'Handle ' + inttostr(hMyApp);
         Windows.SetParent(hMyApp, vWinHnd); //Parent mit Windows.SetParent
         ShowWindow(hMyApp, SW_MAXIMIZE);
      finally
         Releasedc(0, hMyApp);
      end;
   end;

   if Key = ord(27) then
   begin
      Application.Terminate;
   end;
end;

UPDATE

I now tried the following (without SetParent and ShowWindow, using "/P" and "/p"), but that didn't work either:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
   hMyApp: hwnd; //Handle auf das Window welches man im Form braucht
   vWinHnd: hwnd;
   VExePfad: string;
   vParam: string;
begin
   if Key = ord(32) then
   begin
      try
         vWinHnd := self.Handle;
         vParam := '/p ' + inttostr(vWinHnd) ;
         vExePfad := 'C:\Windows\System32\Bubbles.scr';
         ShellExecute(0,
            'open',
            PChar(vExePfad),
            PChar(vParam),
            nil,
            SW_SHOWMAXIMIZED);
         //application.ProcessMessages;
         //hMyApp := GetForegroundWindow();
         //Windows.SetParent(vWinHnd,hMyApp ); //Parent mit Windows.SetParent
         form1.Caption := vParam;
         //ShowWindow(hMyApp, SW_SHOWMAXIMIZED  );
      finally
        // Releasedc(0, hMyApp);
      end;
   end;
   if Key = ord(27) then
   begin
      Application.Terminate;
   end;
end;

Solution

  • Remy Lebeau said the answer in a comment:

    Then the screensaver is likely not implemented correctly, as all screensavers are expected to handle the /p parameter for displaying a preview in the OS's own configuration screen. The only other things I can suggest is 1) try using '/p:<hwnd>' instead of '/p <hwnd>', and 2) try using CreateProcess() instead of ShellExecute().

    Here is the code that works thanks to him.

    procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
       Shift: TShiftState);
    var
       vWinHnd: hwnd;
       VExePfad: string;
       vParam: string;
       SI: TStartupInfo;
       PI: TProcessInformation;
    begin
       if Key = ord(32) then
       begin
          try
             vWinHnd := self.Handle;
             vParam := '/p ' + inttostr(vWinHnd);
             vExePfad := 'C:\Windows\System32\Bubbles.scr';
             ZeroMemory(@SI, SizeOf(SI));
             SI.cb := SizeOf(SI);
             SI.dwFlags := STARTF_USESHOWWINDOW;
             SI.wShowWindow := SW_SHOWMAXIMIZED;
             if CreateProcess(nil, PChar(vExePfad + ' ' + vParam),
                nil,
                nil,
                False,
                0,
                nil,
                nil,
                SI,
                PI) then
             begin
                CloseHandle(PI.hThread);
                CloseHandle(PI.hProcess);
             end;
          finally
             Form1.FormStyle := fsNormal;
          end;
       end;
    
       if Key = ord(27) then
       begin
          Application.Terminate;
       end;
    end;
    end.