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