5

I'm writing a small tool that opens programs on specific screens, so that I can set our monitoring screens (1 machine has 2 screens) to reboot overnight and have it restore the monitoring webpages on boot to the correct screens. I had in mind to accomplish this by using .NET's System.Diagnostics.Process class.

I already saw it's possible to open a process and THEN move it somewhere using P/Invokes ( Open notepad to specific location on the screen, and to desired size? ), however I want to set the target screen BEFORE the application opens, so that for example Chrome in Kiosk mode starts properly with this setup.

Does anyone know how to do this?

Community
  • 1
  • 1
  • This looks like something you want to do: [Link][1] [1]: http://stackoverflow.com/questions/13742259/how-to-open-a-wpf-application-in-a-specific-place-on-a-specific-monitor – LueTm Jun 04 '14 at 09:50
  • @LueTm That works if you are the one writing the application that has to start up, but here I'm trying to manipulate an application I'm starting (e.g Chrome) to show up on a specific monitor. System.Diagnostics.Process does not appear to have functions to manipulate windows that way (although I could be overlooking something). – AlexanderYpema_Infi Jun 04 '14 at 09:52
  • I don't think it's possible wihtout P/Invoke. But there are tools out there that do what you want: http://superuser.com/questions/71248/windows-utility-to-save-restore-window-size-position-history – LueTm Jun 04 '14 at 09:55
  • @LueTm I don't mind if I have to use P/Invoke, the problem is more that the window position has to be set BEFORE it opens, which isn't possible with the conventional P/Invoke MoveWindow function I've seen. As for the tool, I've seen there's tools available but I prefer to do it myself; If someone else wrote a program to do it it must be possible. – AlexanderYpema_Infi Jun 04 '14 at 09:57
  • Why is it so important that the position of the window is changed after it was opened? Shouldn't be visible for more than a split second... – LueTm Jun 04 '14 at 10:00
  • @LueTm If you start a forced-fullscreen application like Chrome in kiosk mode, you cannot move it after it has started. Therefore the starting screen must be set before it launches, otherwise you'll just end up with two chrome kiosk windows on one screen. – AlexanderYpema_Infi Jun 04 '14 at 10:02

1 Answers1

4

We created a similar solution not to long ago using the user32.dll's SetWindowPos. While it does not open the program on the desired window, it takes a couple of milliseconds to do so, so not really an issue for your requirement!

You can have a look at the following gist:
https://gist.github.com/reinhardholl/013a7c3fa319beeaf534#file-display-cs

Pay specific attention to the Display class:

    private void ShowAppOnDisplay(App app)
    {
        SetWindowPos(app.Process.MainWindowHandle, 0, _screen.WorkingArea.Left, _screen.WorkingArea.Top, _screen.WorkingArea.Width, _screen.WorkingArea.Height, SWP_SHOWWINDOW);
    }

Let me know if you require some more help!

joe
  • 8,344
  • 9
  • 54
  • 80
Reinhard Höll
  • 375
  • 3
  • 8
  • Does this work for programs that are already fullscreen when they launch? I thought you couldn't move programs, like Chrome in kiosk mode, when they're already fullscreen.. The code looks really nice though! Trying out if I can use your code in my app now. – AlexanderYpema_Infi Jun 04 '14 at 10:21
  • 1
    Yeah, we actually used it for chrome in kiosk mode! The only caveat we encountered was windows's security "features". If a user has any interaction with any of the windows through the mouse or keyboard the application loses the right to access the window handle, event though it was the creator. – Reinhard Höll Jun 04 '14 at 10:56
  • I have it working! I still have one strange bug though! The windows only get moved when I set a breakpoint on SetWindowPos, or do a Thread.Sleep (even if it's just 1ms). I'll accept the answer as correct though, since the code appears functional :) – AlexanderYpema_Infi Jun 04 '14 at 11:33
  • It might be the time that it takes to allocate the window handle to the process. :) – Reinhard Höll Jun 04 '14 at 12:14
  • 1
    Hmm, on further experimentation it refuses to move the fullscreen Chrome Kiosk window. Even if I do things like Thread.Sleep(5000), also if I try to move a program before it has fully started up it fails to move it as well, which is what caused the earlier bug. – AlexanderYpema_Infi Jun 04 '14 at 12:16
  • Note, I fixed the SetWindowPos bug by doing Process.WaitForInputIdle(), the bug I run into now is that it simply refuses to move the fullscreen Chrome kiosk window. – AlexanderYpema_Infi Jun 04 '14 at 12:19
  • Like I explained in the comment above, as soon as you interact with any program your application loses all rights to manage the programs! Windows security feature – Reinhard Höll Jun 04 '14 at 12:25
  • Aah yes. If you look at the Gist provided in App.cs you will see a similar solution! :) Glad you fixed it – Reinhard Höll Jun 04 '14 at 12:27
  • 1
    I don't touch it, I let the program start, which then opens Chrome Kiosk mode (also tried --start-fullscreen) twice on a single screen, despite using your library to move the Window right after it started (tried various Thread.Sleep and .WaitForInputIdle hacks to no avail) – AlexanderYpema_Infi Jun 04 '14 at 12:28
  • It appears that both Chrome and Firefox sometimes fork and kills the original process. As well as being so slow to start up that they require a significant timeout (3000ms+) for the current approach to work.. I'm thinking about just launching two instances of Chrome or Firefox and then using Selenium to put the right websites in the right places.. – AlexanderYpema_Infi Jun 04 '14 at 13:20
  • Maybe try Internet Explorer just to confirm? – Reinhard Höll Jun 04 '14 at 13:24