Reputation: 488
I am trying to restore a minimized, suspended UWP application from another application, but I cant manage to find a workable solution.
Using .NET Core 2.2 and win32 API via PInvoke
I have tried setting the window placement, setting the window position but nothing works. The only reason I find is that the process that I want to restore is suspended. I did some research and the app is a UWP which is managed by the WinRT stack. sadly I cant find a way to resume the process and display it
Every help or suggestion is appreciated.
Process proc = Process.GetProcessesByName("HxOutlook").FirstOrDefault();
if (proc != null)
{
ShowWindow(proc.MainWindowHandle, SW_SHOWNORMAL); // Make the window visible if it was hidden
ShowWindow(proc.MainWindowHandle, SW_RESTORE); // Next, restore it if it was minimized
SetForegroundWindow(proc.MainWindowHandle); // Finally, activate the window
}
Upvotes: 0
Views: 989
Reputation: 9525
I don't actually think that it matters that the window is part of a UWP app, exactly.
You can restore Mail's main window via the Win32 call ShowWindow(hwnd, SW_RESTORE). However, the trick is you have to find the correct window. In Spy++ you can see that it is some window that has a window class "ApplicationFrameWindow" that is associated with the process with module name "APPLICATIONFRAMEHOST" -- these must be artifacts of UWP's implementation.
In order to find the particular "ApplicationFrameWindow" that is Mail's main window, without relying on something mutable or ephemeral like window text, I found that the correct window is the owner of one of the windows associated with the HxOutlook.exe process. There may be a less convoluted to do this but the following works. This is a native command line application obviously:
#include <Windows.h>
#include <psapi.h>
#include <tchar.h>
#include <vector>
DWORD GetProcessByName(const TCHAR* target_process_name)
{
DWORD processes[1024], bytes_returned;
if (!EnumProcesses(processes, sizeof(processes), &bytes_returned))
return 0;
int n = bytes_returned / sizeof(DWORD);
for (int i = 0; i < n; i++) {
auto pid = processes[i];
TCHAR process_name[MAX_PATH] = TEXT("");
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (process) {
HMODULE module;
DWORD bytes_needed;
if (EnumProcessModules(process, &module, sizeof(module), &bytes_needed)) {
GetModuleBaseName(process, module, process_name, sizeof(process_name) / sizeof(TCHAR));
if (_tcscmp(process_name, target_process_name) == 0)
return pid;
}
}
}
return 0;
}
struct HwndFinder {
std::vector<HWND> windows;
DWORD pid;
HwndFinder(DWORD pid) : pid(pid)
{}
};
BOOL CALLBACK EnumWindowsFindProcessWindow(HWND hwnd, LPARAM lParam)
{
DWORD pid;
HwndFinder* param = reinterpret_cast<HwndFinder*>(lParam);
GetWindowThreadProcessId(hwnd, &pid);
if (pid == param->pid) {
param->windows.push_back(hwnd);
}
return TRUE;
}
std::vector<HWND> GetWindowsFromProcessID(DWORD pid)
{
HwndFinder param(pid);
EnumWindows(EnumWindowsFindProcessWindow, reinterpret_cast<LPARAM>(¶m));
return param.windows;
}
int main()
{
auto mail_process = GetProcessByName(TEXT("HxOutlook.exe"));
auto windows = GetWindowsFromProcessID(mail_process);
for (auto window : windows) {
auto owner = GetWindow(window, GW_OWNER);
if (owner)
ShowWindow(owner, SW_RESTORE);
}
return 0;
}
It's finding the process ID for "HxOutlook.exe", enumerating all the windows in which the WNDPROC for the window runs in a thread owned by that process, and then ShowWindow-ing all windows that own those windows, one of which is the main Mail window.
You could do something like the above via platform invoking, or find a simpler way, or put the code above in a DLL and call into it in C# via DLLImport.
Upvotes: 1
Reputation: 488
The Issue wasn't in the fact that the process was suspended but that I couldn't get the correct window handle via the C# API (System.Diagnostics.Process). All credit goes to jwezorek, this is the C# implementation. (It has issues, but it works)
static UInt32 GetProccessByName(string targetProcessName)
{
UInt32[] processes = new UInt32[1024];
UInt32 bytesCopied;
if (!Psapi.EnumProcesses(processes, (UInt32)processes.Length, out bytesCopied))
{
return 0;
}
foreach (var pid in processes)
{
IntPtr handle = Kernel32.OpenProcess(
(Kernel32.ProcessAccessFlags.QueryInformation |
Kernel32.ProcessAccessFlags.VirtualMemoryRead),
false,
(int)pid);
UInt32[] modules = new UInt32[1024];
UInt32 bytesNeeeded;
if (handle != null)
{
if (Psapi.EnumProcessModules(handle, modules, (UInt32)modules.Length, out bytesNeeeded))
{
StringBuilder text = new StringBuilder(1024);
Psapi.GetModuleBaseName(handle, IntPtr.Zero, text, (UInt32)text.Capacity);
if (text.Equals(targetProcessName))
{
return pid;
}
}
}
}
return 0;
}
public static bool EnumProc(IntPtr hWnd, ref SearchData data)
{
UInt32 pid;
User32.GetWindowThreadProcessId(hWnd, out pid);
if(pid == data.PID)
{
data.Windows.Add(hWnd);
}
return true;
}
static List<IntPtr> GetWindowFromProcessID(UInt32 pid)
{
var searchData = new SearchData(pid);
User32.EnumWindows(new User32.EnumWindowsProc(EnumProc), ref searchData);
return searchData.Windows;
}
static void Main(string[] args)
{
var pid = GetProccessByName("HxOutlook.exe");
var windows = GetWindowFromProcessID(pid);
foreach (var window in windows)
{
var owner = User32.GetWindow(window, User32.GetWindowType.GW_OWNER);
if(owner != null)
{
User32.ShowWindow(owner, SW_RESTORE);
}
}
}
Upvotes: 1