Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Launch a process in a designated monitor

Posted on 2008-10-22
14
Medium Priority
?
1,680 Views
Last Modified: 2012-05-05
I want to be able to launch a process in the Secondary monitor. I am using the code below, but it doesn't seem to work. In fact the result is the same, no matter what value do I use for the hIcon field.

Since notepad does remember its last position, I have also tested with a test application that does not set a default monitor and uses the default position when showing up.
const
  SEE_MASK_HMONITOR = $00200000;  // Not defined in ShellAPI unit
 
procedure TForm1.Button2Click(Sender: TObject);
var
  sei : TShellExecuteInfo;
  SecondaryMonitor : Cardinal;
begin
  // Get the Handle to the secondary monitor
  if Screen.MonitorCount = 1 then
    SecondaryMonitor := 0
  else if Screen.PrimaryMonitor = Screen.Monitors[0] then
    SecondaryMonitor := Screen.Monitors[1].Handle
  else
    SecondaryMonitor := Screen.Monitors[0].Handle;
  // Fill in ShellExecuteEx info
  ZeroMemory(@sei,SizeOf(sei));
  sei.cbSize := SizeOf(sei);
  sei.fMask := SEE_MASK_HMONITOR;
  sei.hIcon := SecondaryMonitor;
  sei.lpVerb := 'open';
  sei.lpFile := 'notepad.exe';
  sei.nShow := SW_SHOWMAXIMIZED;
  ShellExecuteEx(@sei);
end;

Open in new window

0
Comment
Question by:momsoft2
[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
  • 6
  • 3
  • 2
  • +2
14 Comments
 
LVL 28

Expert Comment

by:2266180
ID: 22780508
see this discussion for how to do it properly for your own application: http://stackoverflow.com/questions/206400/start-program-on-a-second-monitor

now, I never played with a multimnonitor system, so you will need to do this yourself and report back if it succeeded or not, dn if not, what errors you get (btw,. did you check what error shellexecuteex returnes?it would help if you would give us the code).

look at this function: http://msdn.microsoft.com/en-us/library/ms534603(VS.85).aspx 
you will use this function to get the correct handle of the monitor using the Screen.Monitors[ x ].Left and top as desccribed in the first link. I figure since that works for your own application, getting the handle via monitorfrompoint should return a valid monitor handle which should work fine with shellexecuteex.

but, do not forget to tell us what error code shellexecuteex returns. we kind of need that to debug the issue ;)
0
 

Author Comment

by:momsoft2
ID: 22780941
ShellExecuteEx does not return any error whatsoever. It simply ignores the supplied monitor.

I am already getting the monitor handle using the Screen.Monitors[x].Handle. Getting the handle using the procedure you describe seems like going in circles.

Anyway, I have used GetMonitorInfo to check that the handle provided by TScreen is valid (see below). It gives the correct size of my secondary monitor.

Therefore, I suspect that the problem lies in ShellExecuteEx.
procedure TForm1.Button3Click(Sender: TObject);
var
  SecondaryMonitor : Cardinal;
  mi : TMonitorInfo;
begin
  // Determine the monitor handle using Delphi Screen
  if Screen.MonitorCount = 1 then
    SecondaryMonitor := 0
  else if Screen.PrimaryMonitor = Screen.Monitors[0] then
    SecondaryMonitor := Screen.Monitors[1].Handle
  else
    SecondaryMonitor := Screen.Monitors[0].Handle;
  // Check that the handle is valid
  mi.cbSize := SizeOf(mi);
  GetMonitorInfo(SecondaryMonitor,@mi);
  ShowMessage(Format('The monitor rect is: %d,%d %d,%d',
    [mi.rcMonitor.Left,mi.rcMonitor.Top,mi.rcMonitor.Right,mi.rcMonitor.Bottom]));
end;

Open in new window

0
 
LVL 14

Expert Comment

by:SteveBay
ID: 22781042
Is the program you are trying to launch one of yours? Did you write it or do you access to the source code?  The reason I ask is that the application your are trying to launch may have specific settings requiring it to launch in the same screen location everytime (i.e. ScreenCenter).
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:momsoft2
ID: 22781192
I have tried many different programs, including a test one that does not set any special positioning, i.e. Position := poDefaultPosOnly.
0
 
LVL 28

Accepted Solution

by:
2266180 earned 600 total points
ID: 22781284
steve might be rioght. try a different aproach.

use enumwindows and GetWindowThreadProcessId for each handle and match it to the processid returned by createprocess function (shellexecuteex only returnes a handle which complicates things a bit).

would this be ok for you? I can make a demo, but tomorrow. it's passed midnight here so I'm closing :)
0
 
LVL 28

Expert Comment

by:2266180
ID: 22781301
forgot to mention, after yuo found the handle of the window, use the movewindow function to place it in correct monitor as in my very first link.
0
 

Author Comment

by:momsoft2
ID: 22781465
I was precisely thinking along the same line of placing myself the window in the desired monitor.

I prefer to use ShellExecute because I have had many problems in the past with CreateProcess. Getting the process ID is easy, enumerating processes. But I have a question? How do I ensure that ShellExecute does not return until the main window has been created? I have noticed that the function returns immediately.

Another issue is getting the main window once I have the process ID. What do you suggest?
0
 
LVL 6

Expert Comment

by:ChristianWimmer
ID: 22781918
How does the main code of your test application look like? Delphi applications have a hidden main window that maybe is positioned on the other monitor instead of the real window. In newer Delphi this problem can be solved by adding "Application.MainFormOnTaskbar := True;" Maybe you/we should test this with a window application created by C++/Delphi without any framework (VCL, MFC, ATL ...).

You can wait for an process until it can process input events by calling WaitForInputIdle (http://msdn.microsoft.com/en-us/library/ms687022(VS.85).aspx)
0
 
LVL 6

Expert Comment

by:ChristianWimmer
ID: 22781937
"Maybe you/we should test this with a window application created by C++/Delphi without any framework (VCL, MFC, ATL ...). "
Sorry, I mean the whole problem! I'll check it in C++ when I have time.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 22783279
when you want your app to start on a second monitor,
i suppose you want all your forms to open on that same monitor
or where the app is residing at that moment

when you open a secondary form you need to set it to poOwnerFormCenter
and create your forms with passing the form calling it

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Self);
  try
    // do stuff with Form2
  finally
    FreeAndNil(Form2);
  end;
end;

also when autocreating the forms in the dpr
change the owner of the second, third, etc forms from
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);

to
Application.CreateForm(TForm1, Form1);
Form2 := TForm2.Create(Form1);

For the initial form i need to look into code at work
I think i solved this issue once

0
 

Author Comment

by:momsoft2
ID: 22783799
I see from the comments received that I have not expressed myself correctly. My needs are to find a general way to launch ANY application and place it in a secondary monitor.

When I found the new functionality in SellExecuteEx, I thought that this was the correct approach, but I have discovered that it is not.

Therefore, the way to go seems to be:

1) Use ShellExecuteEx to launch the application.
2) Obtain the process ID by enumerating all running processes.
3) Use WaitForInputIdle to wait for the application window to be created.
4) Determine the main window of the application using EnumWindows.
5) Manually move the main window to the secondary monitor using MoveWindow.

I will create a test application and post it here for your comments. But so far, your comments are really helping me to solve this problem. Thank you all very much!
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 22783911
with CreateProcess you have direct access to the process id

var
  ProcessInfo: TProcessInformation;
  StartupInfo: TStartupInfo;
  BatchFile: string; // example: "notepad.exe"

FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
with StartupInfo do
begin
  cb:= SizeOf(TStartupInfo);
  dwFlags:= STARTF_USESHOWWINDOW;
  wShowWindow:= SW_SHOWNORMAL;
end;

{ Execute batch file as separated process }
CreateProcess(PChar(BatchFile), nil, nil, nil, False, NORMAL_PRIORITY_CLASS,
    nil, nil, StartupInfo, ProcessInfo);

see ProcessInfo.hProcess for the processid
0
 

Author Closing Comment

by:momsoft2
ID: 31508883
Your suggestion helped me a lot. I have not yet been able to make a test that works, but I am in the right track. If I get stuck, I'll post a new question. Thank you very much.
0
 

Author Comment

by:momsoft2
ID: 22854211
I am working on a complete example, using the suggestions given in your comments. I have not finished it yet but it seems to be the way to go. Thank you all very much.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

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

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
Suggested Courses

721 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