1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file.
4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System;
6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Collections.Generic;
7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.ComponentModel;
8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Data;
9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Diagnostics;
10d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Drawing;
11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.IO;
12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Linq;
13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Management;
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Text;
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Threading.Tasks;
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Windows.Forms;
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using ChromeDebug.LowLevel;
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace ChromeDebug {
21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The form that is displayed to allow the user to select processes to attach to.  Note that we
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // cannot interact with the DTE object from here (I assume this is because the dialog is running
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // on a different thread, although I don't fully understand), so any access to the DTE object
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // will have to be done through events that get posted back to the main package thread.
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  public partial class AttachDialog : Form {
26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private class ProcessViewItem : ListViewItem {
27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public ProcessViewItem() {
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        Category = ProcessCategory.Other;
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        MachineType = LowLevelTypes.MachineType.UNKNOWN;
30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
32d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public string Exe;
33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public int ProcessId;
34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public int SessionId;
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public string Title;
36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public string DisplayCmdLine;
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public string[] CmdLineArgs;
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public ProcessCategory Category;
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public LowLevelTypes.MachineType MachineType;
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      public ProcessDetail Detail;
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private Dictionary<ProcessCategory, List<ProcessViewItem>> loadedProcessTable = null;
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private Dictionary<ProcessCategory, ListViewGroup> processGroups = null;
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private List<int> selectedProcesses = null;
47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
48d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    public AttachDialog() {
49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InitializeComponent();
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      loadedProcessTable = new Dictionary<ProcessCategory, List<ProcessViewItem>>();
52d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      processGroups = new Dictionary<ProcessCategory, ListViewGroup>();
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      selectedProcesses = new List<int>();
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // Create and initialize the groups and process lists only once. On a reset
56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // we don't clear the groups manually, clearing the list view should clear the
57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // groups. And we don't clear the entire processes_ dictionary, only the
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // individual buckets inside the dictionary.
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      foreach (object value in Enum.GetValues(typeof(ProcessCategory))) {
60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        ProcessCategory category = (ProcessCategory)value;
61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        ListViewGroup group = new ListViewGroup(category.ToGroupTitle());
63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        processGroups[category] = group;
64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        listViewProcesses.Groups.Add(group);
65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        loadedProcessTable[category] = new List<ProcessViewItem>();
67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Provides an iterator that evaluates to the process ids of the entries that are selected
71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // in the list view.
72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    public IEnumerable<int> SelectedItems {
73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      get {
74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        foreach (ProcessViewItem item in listViewProcesses.SelectedItems)
75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          yield return item.ProcessId;
76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
78d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
79d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void AttachDialog_Load(object sender, EventArgs e) {
80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      RepopulateListView();
81d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
82d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
83d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Remove command line arguments that we aren't interested in displaying as part of the command
84d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // line of the process.
85d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private string[] FilterCommandLine(string[] args) {
86d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Func<string, int, bool> AllowArgument = delegate(string arg, int index) {
87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (index == 0)
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          return false;
89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return !arg.StartsWith("--force-fieldtrials", StringComparison.CurrentCultureIgnoreCase);
90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      };
91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // The force-fieldtrials command line option makes the command line view useless, so remove
93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // it.  Also remove args[0] since that is the process name.
94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      args = args.Where(AllowArgument).ToArray();
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return args;
96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void ReloadNativeProcessInfo() {
99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      foreach (List<ProcessViewItem> list in loadedProcessTable.Values) {
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        list.Clear();
101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Process[] processes = Process.GetProcesses();
104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      foreach (Process p in processes) {
105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        ProcessViewItem item = new ProcessViewItem();
106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        try {
107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          item.Detail = new ProcessDetail(p.Id);
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          if (item.Detail.CanReadPeb && item.Detail.CommandLine != null) {
109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            item.CmdLineArgs = Utility.SplitArgs(item.Detail.CommandLine);
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            item.DisplayCmdLine = GetFilteredCommandLineString(item.CmdLineArgs);
111d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          }
112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          item.MachineType = item.Detail.MachineType;
113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        catch (Exception) {
115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // Generally speaking, an exception here means the process is privileged and we cannot
116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // get any information about the process.  For those processes, we will just display the
117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // information that the Framework gave us in the Process structure.
118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // If we don't have the machine type, its privilege level is high enough that we won't be
121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // able to attach a debugger to it anyway, so skip it.
122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (item.MachineType == LowLevelTypes.MachineType.UNKNOWN)
123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          continue;
124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.ProcessId = p.Id;
126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.SessionId = p.SessionId;
127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.Title = p.MainWindowTitle;
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.Exe = p.ProcessName;
129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (item.CmdLineArgs != null)
1308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          item.Category = DetermineProcessCategory(item.Detail.Win32ProcessImagePath,
1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                                   item.CmdLineArgs);
132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        Icon icon = item.Detail.SmallIcon;
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        List<ProcessViewItem> items = loadedProcessTable[item.Category];
135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.Group = processGroups[item.Category];
136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        items.Add(item);
137d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
138d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
139d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
140d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Filter the command line arguments to remove extraneous arguments that we don't wish to
141d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // display.
142d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private string GetFilteredCommandLineString(string[] args) {
143d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (args == null || args.Length == 0)
144d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return string.Empty;
145d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      args = FilterCommandLine(args);
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return string.Join(" ", args, 0, args.Length);
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Using a heuristic based on the command line, tries to determine what type of process this
151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // is.
1528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    private ProcessCategory DetermineProcessCategory(string imagePath, string[] cmdline) {
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (cmdline == null || cmdline.Length == 0)
154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return ProcessCategory.Other;
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      string file = Path.GetFileName(imagePath);
157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (file.Equals("delegate_execute.exe", StringComparison.CurrentCultureIgnoreCase))
158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return ProcessCategory.DelegateExecute;
159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      else if (file.Equals("chrome.exe", StringComparison.CurrentCultureIgnoreCase)) {
160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          if (cmdline.Contains("--type=renderer"))
161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              return ProcessCategory.Renderer;
162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          else if (cmdline.Contains("--type=plugin") || cmdline.Contains("--type=ppapi"))
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              return ProcessCategory.Plugin;
164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          else if (cmdline.Contains("--type=gpu-process"))
165d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              return ProcessCategory.Gpu;
166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          else if (cmdline.Contains("--type=service"))
167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              return ProcessCategory.Service;
168d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          else if (cmdline.Any(arg => arg.StartsWith("-ServerName")))
169d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              return ProcessCategory.MetroViewer;
170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          else
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              return ProcessCategory.Browser;
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      } else
173d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return ProcessCategory.Other;
174d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
175d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
176d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void InsertCategoryItems(ProcessCategory category) {
177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      foreach (ProcessViewItem item in loadedProcessTable[category]) {
1788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        item.Text = item.Exe;
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.SubItems.Add(item.ProcessId.ToString());
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.SubItems.Add(item.Title);
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.SubItems.Add(item.MachineType.ToString());
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.SubItems.Add(item.SessionId.ToString());
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        item.SubItems.Add(item.DisplayCmdLine);
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        listViewProcesses.Items.Add(item);
1858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        Icon icon = item.Detail.SmallIcon;
1878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        if (icon != null) {
1888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          item.ImageList.Images.Add(icon);
1898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          item.ImageIndex = item.ImageList.Images.Count - 1;
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        }
191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void AutoResizeColumns() {
195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // First adjust to the width of the headers, since it's fast.
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      listViewProcesses.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
198d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // Save the widths so we can use them again later.
199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      List<int> widths = new List<int>();
200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      foreach (ColumnHeader header in listViewProcesses.Columns)
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        widths.Add(header.Width);
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // Now let Windows do the slow adjustment based on the content.
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      listViewProcesses.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // Finally, iterate over each column, and resize those columns that just got smaller.
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      int total = 0;
2088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      for (int i = 0; i < listViewProcesses.Columns.Count; ++i) {
209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // Resize to the largest of the two, but don't let it go over a pre-defined maximum.
210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        int max = Math.Max(listViewProcesses.Columns[i].Width, widths[i]);
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        int capped = Math.Min(max, 300);
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // We do still want to fill up the available space in the list view however, so if we're
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        // under then we can fill.
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        int globalMinWidth = listViewProcesses.Width - SystemInformation.VerticalScrollBarWidth;
216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (i == listViewProcesses.Columns.Count - 1 && (total + capped) < (globalMinWidth - 4))
217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          capped = globalMinWidth - total - 4;
218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        total += capped;
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        listViewProcesses.Columns[i].Width = capped;
221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void RepopulateListView() {
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      listViewProcesses.Items.Clear();
2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      listViewProcesses.SmallImageList = new ImageList();
2278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      listViewProcesses.SmallImageList.ImageSize = new Size(16, 16);
228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ReloadNativeProcessInfo();
230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.Browser);
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.Renderer);
233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.Gpu);
234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.Plugin);
235d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.MetroViewer);
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.Service);
237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      InsertCategoryItems(ProcessCategory.DelegateExecute);
238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!checkBoxOnlyChrome.Checked)
239d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        InsertCategoryItems(ProcessCategory.Other);
240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      AutoResizeColumns();
242d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void buttonRefresh_Click(object sender, EventArgs e) {
245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      RepopulateListView();
246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
247d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void buttonAttach_Click(object sender, EventArgs e) {
249d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      System.Diagnostics.Debug.WriteLine("Closing dialog.");
250d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      this.Close();
251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private void checkBoxOnlyChrome_CheckedChanged(object sender, EventArgs e) {
254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!checkBoxOnlyChrome.Checked)
255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        InsertCategoryItems(ProcessCategory.Other);
256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      else {
257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        foreach (ProcessViewItem item in loadedProcessTable[ProcessCategory.Other]) {
258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          listViewProcesses.Items.Remove(item);
259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
264