Solved

delphi switch a running application to another monitor

Posted on 2014-10-29
9
852 Views
Last Modified: 2014-10-31
In Delphi, how can I tell another running application to switch from one monitor to another?
0
Comment
Question by:plumothy
  • 5
  • 4
9 Comments
 
LVL 26

Expert Comment

by:Sinisa Vuk
ID: 40411874
Depending on how you set second monitor: mirror, clone, extend first one,....
If you extend windows desktop there is windows api: SetWindowPos
Simply find second app window handle (FindWindow) and set position:
setWindowPos(SecAppHandle, HWND_TOPMOST, x1, y1, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);

Open in new window


width, height with 0 = don't change size - just move
0
 
LVL 26

Expert Comment

by:Sinisa Vuk
ID: 40411985
forgot ... x1 is width of first screen (Screen.Width) + x pos on second screen.
0
 

Author Comment

by:plumothy
ID: 40412647
Sinisa Vuk,
Many thanks for your response. Unfortunately, it does not work for me.

My app is running on Monitor[0] while a Powerpoint presentation is being shown on a projector (Monitor[1]) - while displays are in Extended mode.

My app successfully switches the displays to Duplicate mode in order to show itself on the projector and the laptop at the same time.

Then, I want it to switch back to extended mode. This works OK but the slide show window is still on Monitor[0], so I want to put it back on Monitor[1]. Hence my question.

Here is my code after your response:
procedure TfrmMain.actDuplicateDisplaysExecute(Sender: TObject);
begin
  FSlideShowX := Screen.Monitors[0].Width;   // remembers width of primary monitor (was initialised to -1)
  ShellExecute(0, 'open', 'DisplaySwitch.exe', '/clone', '', 0);  // switches display into Duplicate mode
  Application.BringToFront;  // ensures this app comes to the front
end;


procedure TfrmMain.actExtendDisplayExecute(Sender: TObject);
var
  hSlideShowWindow: hwnd;
begin
  if Screen.MonitorCount > 1 then begin      // only execute this if there is more than one monitor
    ShellExecute(0, 'open', 'DisplaySwitch.exe', '/extend', '', 0);  // switch display into Extended mode
    hSlideShowWindow := GetWindowHandle('Slide Show');   // find the powerpoint slide show window handle
    if ((hSlideShowWindow <> 0) and (FSlideShowX > -1)) then begin       // if the slide show window was found and its X position has been previously stored
      SetWindowPos(hSlideShowWindow, HWND_TOPMOST, FSlideShowX, 0, 0, 0, SWP_SHOWWINDOW);  // set the new position of the slide show window
    end;
  end;
end;

Open in new window

Clearly, I am still doing something wrong.
Can you see what it is?
0
Three Reasons Why Backup is Strategic

Backup is strategic to your business because your data is strategic to your business. Without backup, your business will fail. This white paper explains why it is vital for you to design and immediately execute a backup strategy to protect 100 percent of your data.

 
LVL 26

Expert Comment

by:Sinisa Vuk
ID: 40412664
this
SetWindowPos(hSlideShowWindow, HWND_TOPMOST, FSlideShowX, 0, 0, 0, SWP_SHOWWINDOW); 

Open in new window

is wrong. Don't use SWP_SHOWWINDOW - but SWP_NOSIZE instead.
0
 

Author Comment

by:plumothy
ID: 40412845
OK, done that. However, I have noticed that there is a delay of a few seconds after calling DisplaySwitch.exe while Windows actually switches into Extended mode.

This means that my call to SetWindowPos is occurring too early. To test this theory I made it wait 10 seconds (sleep) before calling SetWindwPos.

While this works, it is not very satisfactory. So, I show a message telling the user to click OK after the display has finished switching - then it calls SetWindowPos. This is better, but still not ideal.

Is there a proper way of delaying the call to SetWindowPos until after the display has finished switching?
0
 
LVL 26

Expert Comment

by:Sinisa Vuk
ID: 40413347
this is very simple solution - just wait for MonitorCount changes:
var
  scr: TScreen;
  monNum: Integer;
begin
  while True do
  begin
    scr := TScreen.Create(Application);
    try
      monNum := scr.MonitorCount;
    finally
      scr.Free;
    end;
    if monNum > 1 then Break;
    Sleep(100);
    Self.Repaint;
  end;

Open in new window


- you can add Timeout option too - to be safe. TScreen will make list on its creation.
0
 

Author Comment

by:plumothy
ID: 40415158
Sinisa Vuk,

Many thanks for your help. It is almost working as I would like it.

The only issue now is that SetWindowPos doesn't set the Powerpoint slide show window in the same position each time it is called (even though the parameters given to it are always the same).

When my application's main form is created I store the width of the primary monitor in a field called FSlideShowX (which is 720 on my laptop).

The user starts their slide show and eventually switches to my app and presses a hot key to get it to call "DisplaySwitch.exe /clone". They do what they need to do in my app and when it is time, they press another hot key to switch back to extended mode. I wait for the switch using your code (with a timeout) and then call:
SetWindowPos(hSlideShowWindow, HWND_TOPMOST, FSlideShowX, 0, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);

Open in new window

The user can switch between them as often as they need to.

That works except each successive call to SetWindowPos puts the slideshow in a slightly different position. It gradually creeps down and to the right even though the X and Y values being passed to it are always 720 and 0 respectively.

Do you have any idea what might be causing that?
0
 
LVL 26

Accepted Solution

by:
Sinisa Vuk earned 500 total points
ID: 40415179
try use another api function:

var
  r: TRect;
begin
  GetWindowRect(PPHandle, r);
  MoveWindow(PPHandle, 0, 0, (r.Right-r.Left), (r.Bottom-r.Top), True);

Open in new window

0
 

Author Closing Comment

by:plumothy
ID: 40415346
Sinisa Vuk

That now works perfectly - thank you.

I did not use GetWindowRect because the laptop and projector might have different resolutions. Instead, I used the BoundRect of the 2nd monitor after switching to extended display mode.
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi Form ownership 4 90
Error E2158 compiling with Delphi XE10 Seattle 2 100
CheckListBox usage 3 59
How to build JSON File in Delphi 6 3 34
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question