【问题标题】:Getting a list of all applications获取所有应用程序的列表
【发布时间】:2013-01-08 02:49:29
【问题描述】:

我正在尝试获取所有打开的应用程序的列表。具体来说,如果您打开任务管理器并转到应用程序选项卡,就会出现该列表。

我试过用这样的东西:

foreach (var p in Process.GetProcesses())
{
    try
    {
        if (!String.IsNullOrEmpty(p.MainWindowTitle))
        {
            sb.Append("\r\n");
            sb.Append("Window title: " + p.MainWindowTitle.ToString());
            sb.Append("\r\n");
        }
    }
    catch
    {
    }
}

就像我发现的几个示例一样,但这并不能为我提取所有应用程序。它只抓取了我在任务管理器中可以看到的或者我知道我已经打开的大约一半。例如,由于某种原因,此方法不支持 Notepad++ 或 Skype,但支持谷歌浏览器、计算器和 Microsoft Word。

有谁知道为什么这不能正常工作或如何做到这一点?

另外,一位朋友建议这可能是权限问题,但我以管理员身份运行 Visual Studio 并且它没有改变。

编辑:我遇到的问题是,我得到的大多数解决方案只返回一个所有进程的列表,这不是我想要的。我只想要打开的应用程序或窗口,例如任务管理器上显示的列表。不是每个进程的列表。

另外,我知道这里有错误的代码,包括空的 catch 块。这是一个一次性项目,只是为了弄清楚它是如何工作的。

【问题讨论】:

  • 可能是因为这些应用没有主窗口标题。
  • 如果你的程序有一个主窗口标题,你可以做这样的事情 Chris Process[] processes = Process.GetProcesses(); foreach (var proc in processes) { if (!string.IsNullOrEmpty(proc.MainWindowTitle)) Console.WriteLine(proc.MainWindowTitle); } 你也可以使用WMImsdn.microsoft.com/en-us/library/windows/desktop/…
  • 您是否还在查看您正在复制和粘贴的代码?
  • 并且,从不使用 try 和空的 catch { }。它只会掩盖错误并使错误无法找到。这就像说“我不在乎这是否有效。”
  • 克里斯我为你找到了一个可行的解决方案,我刚刚对其进行了测试,它会在应用程序选项卡上获取那些正在运行的进程,请参阅我更新的帖子

标签: c# process


【解决方案1】:

代码示例here 似乎可以满足您的要求。修改版:

public class DesktopWindow
{
    public IntPtr Handle { get; set; }
    public string Title { get; set; }
    public bool IsVisible { get; set; }
}

public class User32Helper
{
    public delegate bool EnumDelegate(IntPtr hWnd, int lParam);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWindowVisible(IntPtr hWnd);

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

    [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows",
        ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction,
        IntPtr lParam);

    public static List<DesktopWindow> GetDesktopWindows()
    {
        var collection = new List<DesktopWindow>();
        EnumDelegate filter = delegate(IntPtr hWnd, int lParam)
        {
            var result = new StringBuilder(255);
            GetWindowText(hWnd, result, result.Capacity + 1);
            string title = result.ToString();

            var isVisible = !string.IsNullOrEmpty(title) && IsWindowVisible(hWnd);

            collection.Add(new DesktopWindow { Handle = hWnd, Title = title, IsVisible = isVisible });

            return true;
        };

        EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero);
        return collection;
    }
}

使用上面的代码,调用User32Helper.GetDesktopWindows() 应该会给你一个包含所有打开的应用程序的句柄/标题的列表,以及它们是否可见。请注意,无论窗口是否可见,都会返回 true,因为该项目仍会按照作者的要求显示在任务管理器的应用程序列表中。

然后,您可以使用集合中某个项目的相应 Handle 属性,使用其他 Window Functions(例如 ShowWindowEndTask)执行许多其他任务。

【讨论】:

  • 效果很好。如果您尝试关闭特定窗口而不是整个应用程序,我推荐这个answer。 DestroyWindow (msdn.microsoft.com/en-us/library/windows/desktop/…) 只能在同一个线程中工作,而 CloseWindow (msdn.microsoft.com/en-us/library/windows/desktop/…) 只会最小化目标窗口。
  • 我试过这个。但它只在一定程度上起作用。它仍然显示一些目前未打开的后台应用程序,例如新闻、设置、计算器、Netflix 等。但我能够在任务管理器的“后台进程”部分看到这些进程。有什么方法可以获取任务栏或任务管理器“应用程序”部分中显示的应用程序列表。
【解决方案2】:

正如马修所说,这可能是因为它们没有主要标题,因此您将它们过滤掉了。下面的代码让所有进程运行。然后您可以使用Process.ProcessName 过滤掉您不想要的那个。 Here 是关于使用 ProcessName 的文档。

using System.Diagnostics;

Process[] processes = Process.GetProcesses();

foreach (Process process in processes)
{
   //Get whatever attribute for process
}

【讨论】:

  • 我想我很困惑的是我不知道我想要过滤什么,如果这有意义的话。我知道我想要所有正在运行的应用程序,但我该如何检查呢?我在这件事上看到的大多数事情是,如果一个应用程序有一个窗口,它就有一个 MainWindowTitle,那么我如何获得像 Notepad++ 这样显然没有的东西?
  • @ChrisBacon 它仍然有一个进程名或进程ID,如果它正在运行!
【解决方案3】:

我认为,出于某种原因,某些进程的 MainWindowTitle 为空,因此您正在跳过这些进程。试试这个只是为了测试:

foreach (var p in Process.GetProcesses())
{
     sb.Append("\r\n");
     sb.Append("Process Name: " + p.ProcessName);
     sb.Append("\r\n");
}

如果你的 try...catch 出现错误,可能会跳过一些进程,所以也尝试不使用它。

更新: 试试这个,它很丑,并且采取一些没有窗口但也许你可以过滤的进程..

var proc = new Process()
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "tasklist",
        Arguments = "/V",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};
proc.Start();
StreamReader sr = proc.StandardOutput;
while (!sr.EndOfStream)
{
    string line = sr.ReadLine();
    Match m = Regex.Match(line, @".{52}(\d+).{94}(.+)$");//157
    if (m.Success)
    {
        int session = Convert.ToInt32(m.Groups[1].Value);
        string title = m.Groups[2].Value.Trim();
        if (session == 1 && title != "N/A") sb.AppendLine(title);
    }
}

【讨论】:

  • 我试着去掉 try/catch 块,但它仍然忽略了一些窗口。主要问题是我不想要每一个进程,我只想要那些与它们相关联的窗口。
  • 克里斯,你的代码在我的电脑上运行,包括 Skype 和 Notepad++。您使用的是哪些 Windows 和框架版本?
【解决方案4】:

正如其他人所说,这是因为某些应用程序(Notepad++ 就是其中之一)没有 MainWindowTitle,为了解决这个问题,我的代码(例如)如下所示:

Process[] processes = Process.GetProcesses();

foreach (Process pro in processes)
{
    if (pro.MainWindowTitle != "")
    {
        listBox.Items.Add(pro.ProcessName + " - " + pro.MainWindowTitle);
    }
    else
    {
        listBox.Items.Add(pro.ProcessName);
    }
}

【讨论】:

  • 我对这个解决方案的问题是它仍然只是让我运行每个进程,这不是我想要的。我只想要带有 Windows 的进程。基本上我想要的只是我可以在任务管理器的应用程序选项卡中看到的应用程序。
【解决方案5】:

你可以试试这样的克里斯

//下面的更新将为您提供在应用程序选项卡中运行的所有进程

Process[] myProcesses = Process.GetProcesses();

foreach (Process P in myProcesses)
{
    if (P.MainWindowTitle.Length > 1)
    {
        Console.WriteLine(P.ProcessName + ".exe");
        Console.WriteLine(" " + P.MainWindowTitle);
        Console.WriteLine("");
    }
}

【讨论】:

  • 我对这个解决方案的问题是它仍然只是让我运行每个进程,这不是我想要的。我想要进程带有窗口。基本上我想要的只是我可以在任务管理器的应用程序选项卡中看到的应用程序。
猜你喜欢
  • 2010-09-08
  • 1970-01-01
  • 2014-06-29
  • 1970-01-01
  • 2013-01-20
  • 1970-01-01
  • 1970-01-01
  • 2016-12-29
  • 2010-12-23
相关资源
最近更新 更多