Name of Process for Active Window in Windows 8/10

Name of process for active window in Windows 8/10

Be sure to use the Spy++ utility when you want to reverse-engineer something like this. Included with Visual Studio, you need the 64-bit version in Common7\Tools\spyxx_amd64.exe. Use Search > Find Window and drag the bullseye to a UWP app, like Weather.

You'll see the window you'll find with GetForegroundWindow(), it has at least 3 child windows:

  • ApplicationFrameTitleBarWindow
  • ApplicationFrameInputSinkWindow
  • Windows.Core.UI.CoreWindow, that's the host window for the UWP app and the one you are interested in. Right-click it and select Properties, Process tab, click the Process ID. That takes you to the real owner process you want to know.

So you just need to make an extra step from the code you already have, you just have to enumerate the child windows and look for one with a different owner process. Some C code, trying to make it as universal as possible without making too many assumptions and not enough error checking:

#include <stdio.h>
#include <Windows.h>

typedef struct {
DWORD ownerpid;
DWORD childpid;
} windowinfo;

BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lp) {
windowinfo* info = (windowinfo*)lp;
DWORD pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
if (pid != info->ownerpid) info->childpid = pid;
return TRUE;
}

int main()
{
Sleep(2000);
HWND active_window = GetForegroundWindow();
windowinfo info = { 0 };
GetWindowThreadProcessId(active_window, &info.ownerpid);
info.childpid = info.ownerpid;
EnumChildWindows(active_window, EnumChildWindowsCallback, (LPARAM)&info);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, info.childpid);
WCHAR image_name[MAX_PATH] = { 0 };
DWORD bufsize = MAX_PATH;
QueryFullProcessImageName(active_process, 0, image_name, &bufsize);
wprintf(L"%s\n", image_name);
CloseHandle(active_process);
return 0;
}

Output on the Weather program:

C:\Program Files\WindowsApps\Microsoft.BingWeather_4.5.168.0_x86__8wekyb3d8bbwe\
Microsoft.Msn.Weather.exe

How can I get the process name of the current active window in windows with winapi?

You can use GetWindowThreadProcessId(), which takes in an HWND and outputs the ID of the window's owning process.

For example:

#include <tchar.h>

TCHAR wnd_title[256];
HWND hwnd = GetForegroundWindow(); // get handle of currently active window
GetWindowTextA(hwnd, wnd_title, 256);

DWORD dwPID;
GetWindowThreadProcessId(hwnd, &dwPID);

HANDLE Handle = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
dwPID
);
if (Handle)
{
TCHAR Buffer[MAX_PATH];
if (GetModuleFileNameEx(Handle, 0, Buffer, MAX_PATH))
{
_tprintf(_T("Path: %s"), Buffer);
// At this point, buffer contains the full path to the executable
}
CloseHandle(Handle);
}

Proper way of activating a window using WinAPI

The solution I finally used combines restoring window when it is minimized and then using UI automation API.

I suppose that the most credit goes to Simon Mourier, who proposed the solution in a comment.

Relevant parts of code follows:

int main(int argc, const char* const argv[])
{
if (!SUCCEEDED(CoInitialize(nullptr)))
{
return 1;
}
// (...)
}

SwitchToPlugin::SwitchToPlugin()
{
if (!SUCCEEDED(CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&(this->uiAutomation))))
{
throw new std::exception("Failed to create instance of UI automation!");
}
}

/// <summary>
/// Brings given window to the front
/// </summary>
bool SwitchToPlugin::bring_to_front(HWND hWnd)
{
bool result = false;

// First restore if window is minimized

WINDOWPLACEMENT placement{};
placement.length = sizeof(placement);

if (!GetWindowPlacement(hWnd, &placement))
return false;

bool minimized = placement.showCmd == SW_SHOWMINIMIZED;
if (minimized)
ShowWindow(hWnd, SW_RESTORE);

// Then bring it to front using UI automation

IUIAutomationElement* window = nullptr;
if (SUCCEEDED(uiAutomation->ElementFromHandle(hWnd, &window)))
{
if (SUCCEEDED(window->SetFocus()))
{
result = true;
}

window->Release();
}

return result;
}

So far works all the time and contains no hacks and other tricks. Tested on Spotify, Notepad, Teams and Visual Studio.

Full source of the plugin is available on GitLab: https://gitlab.com/spook/StreamDeckSwitchTo.git

Determining the Active Window name or id

You need to use Pinvoke to execute some Win32 API to get all this info.
Below is the sequence of Pinvoke that you need to use.

  • GetForegroundWindow (to get current active window handle - hwnd)
  • GetWindowThreadProcessId (to get the process ID and thread ID for the hwnd that you got in the above API call)

How to get active window app name as shown in task manager

After reading a lot, I separated my code into two cases, for metro application and all other applications.
My solution handle the exception I got for metro applications and exceptions I got regarding the platform.
This is the code that finally worked:

[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

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

public string GetActiveWindowTitle()
{
var handle = GetForegroundWindow();
string fileName = "";
string name = "";
uint pid = 0;
GetWindowThreadProcessId(handle, out pid);

Process p = Process.GetProcessById((int)pid);
var processname = p.ProcessName;

switch (processname)
{
case "explorer": //metro processes
case "WWAHost":
name = GetTitle(handle);
return name;
default:
break;
}
string wmiQuery = string.Format("SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId LIKE '{0}'", pid.ToString());
var pro = new ManagementObjectSearcher(wmiQuery).Get().Cast<ManagementObject>().FirstOrDefault();
fileName = (string)pro["ExecutablePath"];
// Get the file version
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
// Get the file description
name = myFileVersionInfo.FileDescription;
if (name == "")
name = GetTitle(handle);

return name;
}

public string GetTitle(IntPtr handle)
{
string windowText = "";
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
if (GetWindowText(handle, Buff, nChars) > 0)
{
windowText = Buff.ToString();
}
return windowText;
}

How to get path of current active application window?

You can't use GetWindowModuleFileName to locate files for other processes than your own, as stated on GetModuleFileName MSDN:

Retrieves the fully-qualified path for the file that contains the specified module. The module must have been loaded by the current process.

To locate the file for a module that was loaded by another process,
use the GetModuleFileNameEx function.

Therefore, you have to use GetModuleFileNameEx combined with GetWindowThreadProcessId/GetForegroundWindow. This will return you what you need:

uses
Winapi.Windows, Winapi.PsAPI, System.SysUtils;

function GetCurrentActiveProcessPath: String;
var
pid : DWORD;
hProcess: THandle;
path : array[0..4095] of Char;
begin
GetWindowThreadProcessId(GetForegroundWindow, pid);

hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, pid);
if hProcess <> 0 then
try
if GetModuleFileNameEx(hProcess, 0, @path[0], Length(path)) = 0 then
RaiseLastOSError;

result := path;
finally
CloseHandle(hProcess);
end
else
RaiseLastOSError;
end;


Related Topics



Leave a reply



Submit