我正在尝试为 Windows 10 应用获取一个易于理解的“进程名称”。目前,它们都使用 ApplicationFrameHost
,所以我想我可以使用 ModelId
或 PackageName
,但似乎是 Windows 10 Store Apps (我尝试使用 Mail
、Store
和 Edge
)无法与 Package query API 一起使用
使用 kernel32.dll
,GetApplicationUserModelId
返回 APPMODEL_ERROR_NO_APPLICATION
,GetPackageId
返回 APPMODEL_ERROR_NO_PACKAGE
.
如何获取 Windows 10 应用商店应用程序的标识符,以便我可以唯一地标识,例如 Edge还有任何其他 Windows 10 应用商店应用程序吗?
更新
我从 hWnd
(窗口句柄)获取进程 ID,所以我认为我的问题实际上是如何从窗口句柄获取“真实”进程 ID。从那里开始,使用这些方法可能会奏效。
最佳答案
UWP应用程序被包装到另一个应用程序/进程中。如果它有焦点,则尝试找到子 UWP 进程。
您将需要一些 P/Invoke 方法。看看这个类,它提供了完成这项工作所需的所有代码:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Stackoverflow
{
internal struct WINDOWINFO
{
public uint ownerpid;
public uint childpid;
}
public class UwpUtils
{
#region User32
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
/// <summary>
/// Delegate for the EnumChildWindows method
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
/// <returns>True to continue enumerating, false to bail.</returns>
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
#endregion
#region Kernel32
public const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
public const UInt32 PROCESS_VM_READ = 0x010;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
UInt32 dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)]
Boolean bInheritHandle,
Int32 dwProcessId
);
#endregion
public static string GetProcessName(IntPtr hWnd)
{
string processName = null;
hWnd = GetForegroundWindow();
if (hWnd == IntPtr.Zero)
return null;
uint pID;
GetWindowThreadProcessId(hWnd, out pID);
IntPtr proc;
if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, (int)pID)) == IntPtr.Zero)
return null;
int capacity = 2000;
StringBuilder sb = new StringBuilder(capacity);
QueryFullProcessImageName(proc, 0, sb, ref capacity);
processName = sb.ToString(0, capacity);
// UWP apps are wrapped in another app called, if this has focus then try and find the child UWP process
if (Path.GetFileName(processName).Equals("ApplicationFrameHost.exe"))
{
processName = UWP_AppName(hWnd, pID);
}
return processName;
}
#region Get UWP Application Name
/// <summary>
/// Find child process for uwp apps, edge, mail, etc.
/// </summary>
/// <param name="hWnd">hWnd</param>
/// <param name="pID">pID</param>
/// <returns>The application name of the UWP.</returns>
private static string UWP_AppName(IntPtr hWnd, uint pID)
{
WINDOWINFO windowinfo = new WINDOWINFO();
windowinfo.ownerpid = pID;
windowinfo.childpid = windowinfo.ownerpid;
IntPtr pWindowinfo = Marshal.AllocHGlobal(Marshal.SizeOf(windowinfo));
Marshal.StructureToPtr(windowinfo, pWindowinfo, false);
EnumWindowProc lpEnumFunc = new EnumWindowProc(EnumChildWindowsCallback);
EnumChildWindows(hWnd, lpEnumFunc, pWindowinfo);
windowinfo = (WINDOWINFO)Marshal.PtrToStructure(pWindowinfo, typeof(WINDOWINFO));
IntPtr proc;
if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, (int)windowinfo.childpid)) == IntPtr.Zero)
return null;
int capacity = 2000;
StringBuilder sb = new StringBuilder(capacity);
QueryFullProcessImageName(proc, 0, sb, ref capacity);
Marshal.FreeHGlobal(pWindowinfo);
return sb.ToString(0, capacity);
}
/// <summary>
/// Callback for enumerating the child windows.
/// </summary>
/// <param name="hWnd">hWnd</param>
/// <param name="lParam">lParam</param>
/// <returns>always <c>true</c>.</returns>
private static bool EnumChildWindowsCallback(IntPtr hWnd, IntPtr lParam)
{
WINDOWINFO info = (WINDOWINFO)Marshal.PtrToStructure(lParam, typeof(WINDOWINFO));
uint pID;
GetWindowThreadProcessId(hWnd, out pID);
if (pID != info.ownerpid)
info.childpid = pID;
Marshal.StructureToPtr(info, lParam, true);
return true;
}
#endregion
}
}
现在,使用另一个 P/Invoke 方法获取当前前台窗口的句柄
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
使用返回值并调用上面代码中的 GetProcessName
方法。您应该收到正确的流程名称/路径。
下面是一个简单的表单来测试代码:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using StackOverflow;
namespace Stackoverflow.Test
{
public partial class TestForm : Form
{
WinEventDelegate dele = null;
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
public TestForm()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
textBox1.AppendText(GetActiveWindowTitle() + "\n");
}
private string GetActiveWindowTitle()
{
return UwpUtils.GetProcessName(GetForegroundWindow());
}
}
}
您可以下载完整代码,包括 GitHub 上的示例/测试.
关于c# - 如何从 hWnd 获取 "Application Name"for Windows 10 Store Apps (e.g. Edge),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32001621/