Question

I'm writing a .exe that is supposed to run as a scheduled task to check if I have required IE windows open running .Xbaps on specific monitors. I have code that checks what URL is supposed to run, if it's not I use this code to launch it, then move it to the correct monitor:

Process myProcess = Process.Start("iexplore.exe", "-new -k " + "http://server01:123/software.client.xbap");
myProcess.WaitForInputIdle();
Thread.Sleep(500);
MoveWindowToMonitor(myProcess.MainWindowHandle, 1);

Window Moving code:

private static void MoveWindowToMonitor(IntPtr windowHandler, int monitor)
{
    RECT windowRec = new RECT();
    GetWindowRect(windowHandler, ref windowRec);

    int width = windowRec.Right - windowRec.Left;
    int height = windowRec.Top - windowRec.Bottom;

    if (width < 0)
        width = width * -1;

    if (height < 0)
        height = height * -1;


    SetWindowPos(windowHandler, (IntPtr)SpecialWindowHandles.HWND_TOP, Screen.AllScreens[monitor].WorkingArea.Left,
            Screen.AllScreens[monitor].WorkingArea.Top, width, height, SetWindowPosFlags.SWP_SHOWWINDOW);

}

Running a quick test version of this gets the first IE window open, Xbap launched, and then quickly moves it over to my other monitor. When I run it a second time, without closing the first IE window, I always get InvalidOperationException

"Process has exited, so the requested information is not available."

I've checked my Task Manager as this is happening and I actually get two iexplore.exe items under details the first time I run the task, and only one additional iexplorer.exe for each subsequent execution of the task. I also get one PresentationHost.exe per xbap launched.

Anyone have any idea what I'm doing wrong or a better way to do this? My end goal is to be able to do this:

  • Launch IE in Kiosk Mode on monitor 1 with specific url X:
  • Launch IE in Kiosk Mode on monitor 2 with specific url Y:
Was it helpful?

Solution

After you launch an IE process, it does some funny stuff and that process you have launched can occasionally end right away as another takes over the window.

What I would do is, using the methods below, is EnumTheWindows which would step through every visible window running and look for Internet Explorer or my baseURL. Then I would pass that Window Handle to GetURL and get the specific URL that IE window was running. This allowed me to use ConfirmProcessIsOnProperMonitor() and MoveWindowToMonitor() to get the windows on the proper monitor.

Important stuff:

private static bool ConfirmProcessIsOnProperMonitor(IntPtr windowHandler, int monitor)
{
    //make sure you don't go to an incorrect monitor
    if (monitor >= Screen.AllScreens.Count()) monitor = Screen.AllScreens.Count() - 1;

    RECT windowRec = new RECT();
    GetWindowRect(windowHandler, ref windowRec);

    if (windowRec.Left != Screen.AllScreens[monitor].WorkingArea.Left || windowRec.Top != Screen.AllScreens[monitor].WorkingArea.Top)
        return false;
    else
        return true;
}

private static void MoveWindowToMonitor(IntPtr windowHandler, int monitor)
{
    //make sure you don't go to an incorrect monitor
    if (monitor >= Screen.AllScreens.Count()) monitor = Screen.AllScreens.Count() - 1;

    RECT windowRec = new RECT();
    GetWindowRect(windowHandler, ref windowRec);

    int width = windowRec.Right - windowRec.Left;
    int height = windowRec.Top - windowRec.Bottom;

    if (width < 0)
        width = width * -1;

    if (height < 0)
        height = height * -1;


    SetWindowPos(windowHandler, (IntPtr)SpecialWindowHandles.HWND_TOP, Screen.AllScreens[monitor].WorkingArea.Left,
            Screen.AllScreens[monitor].WorkingArea.Top, width, height, SetWindowPosFlags.SWP_SHOWWINDOW);

}

protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
    int size = GetWindowTextLength(hWnd);
    if (size++ > 0 && IsWindowVisible(hWnd))
    {
        StringBuilder sb = new StringBuilder(size);
        GetWindowText(hWnd, sb, size);
        string windowText = sb.ToString();

        if (windowText.ToLower().Contains(_baseURL) || windowText.ToLower().Contains("internet explorer"))
        {
            string url = GetURL(hWnd);
            _windowhandles.Add(hWnd, url);
        }
    }
    return true;
}

private static string GetURL(IntPtr intPtr)
{
    foreach (InternetExplorer ie in new ShellWindows())
    {
        if (ie.HWND == intPtr.ToInt32())
        {
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(ie.FullName);
            if ((fileNameWithoutExtension != null) && fileNameWithoutExtension.ToLower().Equals("iexplore"))
            {
                return ie.LocationURL;
            }
            else
            {
                return null;
            }
        }
    }

    return null;
}

Hard to read windows API code:

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, StringBuilder msgbody);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top