Solved

delphi switch a running application to another monitor

Posted on 2014-10-29
9
733 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 25

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 25

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
 
LVL 25

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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 

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 25

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 25

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

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
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…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

743 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now