Solved

delphi switch a running application to another monitor

Posted on 2014-10-29
9
1,066 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
9 Comments
 
LVL 27

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 27

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
Create the perfect environment for any meeting

You might have a modern environment with all sorts of high-tech equipment, but what makes it worthwhile is how you seamlessly bring together the presentation with audio, video and lighting. The ATEN Control System provides integrated control and system automation.

 
LVL 27

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 27

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 27

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

[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

Question has a verified solution.

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

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Sometimes a user will call me frantically, explaining that something has gone wrong and they have tried everything (read - they have messed it up more and now need someone to clean up) and it still does no good, can I help them?!  Usually the standa…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…
Suggested Courses
Course of the Month6 days, 3 hours left to enroll

627 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