Projectreunion: Proposal: Add Process.MainWindowHandle to WindowsApps (C#)

Created on 4 Dec 2020  路  9Comments  路  Source: microsoft/ProjectReunion

Get Process.MainWindowHandle for WindowsApps in C

Summary

I would like to maximize the Windows Camera App or the Time App, but it's not possible, because the MainWindowHandle of the Process is just zero (0x0000000000000000). Every other Window like Notepad or what ever is working, but all WindowsApps aren't. Please add this feature, because I don't think that I'm the only one missing this.

Rationale

  • You have the button to maximize and minimize, but you can't do it from code? Why not?

Scope

| Capability | Priority |
| :- | :- |
| Get the MainWindowHandle from a WindowsApp process | Must |

Example

```c#
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public class WindowHandling
{
public void Maximize()
{
Process myProcess = new Process();
Process[] processes = Process.GetProcesses();
if (processes.Length != 0)
{
foreach (Process pro in processes)
{
if (pro.ProcessName == "Time") /* "WindowsCamera" ( Isn't working) / / "notepad" (Is working)*/
{
myProcess = pro;
}
}
var myWindowHandle = myProcess.MainWindowHandle; // with all WindowsApps this is 0x0000000000000000...
ShowWindow(myWindowHandle, 3);
}
}
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
```

area-Windowing

All 9 comments

Transfered to Project Reunion, I'm not sure if this is a windowing issue, a .net api issue or a UWP sandbox feature.

Thanks for transferring! I wasn't sure where to place the proposal, but I think this is the right place now 馃槂

@rkarman - A windowing ask for you!

What you need to do is enumerate all windows with the class ApplicationFrameWindow on the desktop, and find the child with the class Windows.UI.Core.CoreWindow. The owner of this child is the main UWP process, so it's a simple GetWindowThreadProcessId followed by an if check.

In code, it would look like this:

std::vector<HWND> FindAppWindows(DWORD pid)
{
    static constexpr wchar_t FRAME_WINDOW[] = L"ApplicationFrameWindow";

    std::vector<HWND> appWindows;
    for (HWND appWindow = FindWindowEx(nullptr, nullptr, FRAME_WINDOW, nullptr); appWindow;
        appWindow = FindWindowEx(nullptr, appWindow, FRAME_WINDOW, nullptr))
    {
        const HWND coreWindow = FindWindowEx(appWindow, nullptr, L"Windows.UI.Core.CoreWindow", nullptr);
        if (coreWindow)
        {
            DWORD corePid = 0;
            GetWindowThreadProcessId(coreWindow, &corePid);
            if (corePid == pid)
            {
                appWindows.push_back(appWindow);
            }
        }
    }

    return appWindows;
}

@sylveon are you sure, we are speaking the same language? Your code is written in C++, but what I'm looking for is a C# solution...

Thanks for your help

You can PInvoke those methods fine? Your code already PInvokes ShowWindow, and implementing this in C# would be only two more PInvokes, while swapping a few nullptr for IntPtr.Zero or null.

FWIW "main window handle" isn't a concept that exists at the Win32-level and the property that Process exposes is more of a hack/attempt from the .NET team at guessing the right window. It's not always reliable, and this isn't the first case I've seen it fail at getting it right.

Here's the C# equivalent:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

private const string FRAME_WINDOW = "ApplicationFrameWindow";

List<IntPtr> FindAppWindows(Process proc)
{
    var appWindows = new List<IntPtr>();
    for (IntPtr appWindow = FindWindowEx(IntPtr.Zero, IntPtr.Zero, FRAME_WINDOW, null); appWindow != IntPtr.Zero;
        appWindow = FindWindowEx(IntPtr.Zero, appWindow, FRAME_WINDOW, null))
    {
        IntPtr coreWindow = FindWindowEx(appWindow, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
        if (coreWindow != IntPtr.Zero)
        {
            GetWindowThreadProcessId(coreWindow, out var corePid);
            if (corePid == proc.Id)
            {
                appWindows.Add(appWindow);
            }
        }
    }

    return appWindows;
}

You have the button to maximize and minimize, but you can't do it from code? Why not?

You don't need to. Users should be in control of their PCs not apps. I think the same app should be able to minimize themself which is not possible today but other apps should not interfere with an app. Then what's the use of an app container if other apps can do anything? The old desktop model provides all that because security wasn't a concern when Windows was originally launched.

You don't need to. Users should be in control of their PCs not apps. I think the same app should be able to minimize themself which is not possible today but other apps should not interfere with an app. Then what's the use of an app container if other apps can do anything? The old desktop model provides all that because security wasn't a concern when Windows was originally launched.

But why is it possible anyway (like @sylveon explained), if there is something like security measurements to supress it?

Another question is: Why isn't it possible to start the Windows camera app with arguments to maximize?

Was this page helpful?
0 / 5 - 0 ratings