-
Notifications
You must be signed in to change notification settings - Fork 0
/
MainWindow.xaml.cs
329 lines (303 loc) · 10.9 KB
/
MainWindow.xaml.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
using System;
using System.Windows;
using System.IO;
using System.ComponentModel;
using Microsoft.Win32;
using System.Drawing;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Mono.Options;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using System.Windows.Interop;
namespace PinFolder
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public const string title = "PinFolder by Chen Buyi";
private OpenFileDialog? fileDialog = null;
private static string ProcessName = string.Empty;
public MainWindow()
{
ProcessName = Process.GetCurrentProcess().ProcessName;
Environment.CurrentDirectory = AppContext.BaseDirectory;
InitializeComponent();
this.Title = title;
var args = Environment.GetCommandLineArgs();
if (args.Length >= 3)
{
var dir = string.Empty;
var icon = string.Empty;
var options = new OptionSet
{
{ "icon=", s => { icon = s; } },
{ "dir=", v => { dir = v; } }
};
options.Parse(args);
try
{
ShowTaskbarIcon(dir, icon);
this.Hide();
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
}
#region 辅助
public static void ShowError(string message)
{
MessageBox.Show(message, "出错 " + title, MessageBoxButton.OK, MessageBoxImage.Error);
}
private static void OpenProcess(string p)
{
var pinfo = new ProcessStartInfo
{
FileName = p,
UseShellExecute = true
};
using var _ = Process.Start(pinfo);
}
private static void SimpleUITimer(Action act, int timeoutMs)
{
if (timeoutMs < 1) { timeoutMs = 1; }
var t1 = new Task(() =>
{
Thread.Sleep(timeoutMs);
Application.Current.Dispatcher.Invoke(act);
});
t1.Start();
}
private static void MakeControlCoolDown(Control ct, int timeoutMs = 800)
{
ct.IsEnabled = false;
SimpleUITimer(() =>
{
ct.IsEnabled = true;
}, timeoutMs);
}
#endregion
#region 编辑器
public event PropertyChangedEventHandler? PropertyChanged;
public void CallPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private string _targetDir = string.Empty;
public string TargetDir
{
get
{
return _targetDir;
}
set
{
_targetDir = value;
currentDir = null;
icoTaskbar.Visibility = Visibility.Hidden;
CallPropertyChanged(nameof(TargetDir));
}
}
private void BtnOpenFolder_Click(object sender, RoutedEventArgs e)
{
TargetDir = string.Empty;
MakeControlCoolDown(btnOpenFolder);
try
{
fileDialog ??= new Microsoft.Win32.OpenFileDialog
{
Title = "选择这个文件夹里的任意一个子文件即可(但不能是快捷方式)",
CheckFileExists = true,
CheckPathExists = true,
AddExtension = true,
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
};
var ok = fileDialog.ShowDialog();
if (ok != true) { return; }
var dir = Path.GetDirectoryName(fileDialog.FileName);
if (string.IsNullOrWhiteSpace(dir)) { throw new Exception("无法获取这个文件夹的路径"); }
TargetDir = dir;
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private void BtnMakeBat_Click(object sender, RoutedEventArgs e)
{
MakeControlCoolDown(btnMakeBat);
try
{
if (currentDir == null) { throw new Exception("需要先开启预览,然后才能生成"); }
var str = $"start \"\" \"{ProcessName}.exe\" -dir \"{currentDir.FullName}\" -icon \"{lastIconText}\"";
var dir = AppContext.BaseDirectory;
var p = Path.Combine(dir, $"_{currentDir.Name}.bat");
File.WriteAllText(p, str);
OpenProcess(dir);
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private void BtnKillOld_Click(object sender, RoutedEventArgs e)
{
MakeControlCoolDown(btnKillOld);
try
{
var all = Process.GetProcessesByName(ProcessName);
foreach (var proc in all)
{
if (proc.Id != Environment.ProcessId) { proc?.Kill(); }
proc?.Dispose();
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private void BtnPreview_Click(object sender, RoutedEventArgs e)
{
MakeControlCoolDown(btnPreview);
try
{
ShowTaskbarIcon(TargetDir, txtIconChar.Text);
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private void BtnAbout_Click(object sender, RoutedEventArgs e)
{
OpenProcess("https://github.com/chenbuyi2019/PinFolder");
}
#endregion
#region 图标生成
private static readonly SolidBrush backgroundBrush = new(Color.AliceBlue);
private static readonly SolidBrush fontBrush = new(Color.Black);
private const int iconWidth = 128;
private static readonly Font iconFont = new("Microsoft YaHei UI", Convert.ToInt32(iconWidth * 0.75), System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
private static Icon CreateIcon(string text)
{
using var iconBitmap = new Bitmap(iconWidth, iconWidth);
using var g = Graphics.FromImage(iconBitmap);
g.FillRectangle(backgroundBrush, 0, 0, iconWidth, iconWidth);
g.DrawString(text, iconFont, fontBrush, 1, 1);
var icon = System.Drawing.Icon.FromHandle(iconBitmap.GetHicon());
return icon;
}
#endregion
#region 实际菜单
private string lastIconText = string.Empty;
private DirectoryInfo? currentDir = null;
private void ShowTaskbarIcon(string dir, string text)
{
icoTaskbar.Visibility = Visibility.Hidden;
if (string.IsNullOrWhiteSpace(dir)) { throw new Exception("输入的文件夹路径是空白"); }
dir = dir.Trim();
var dirInfo = new DirectoryInfo(dir);
if (!dirInfo.Exists) { throw new Exception("文件夹不存在: " + dir); }
if (string.IsNullOrWhiteSpace(text))
{
text = dirInfo.Name;
}
text = text.Trim()[0].ToString();
lastIconText = text;
currentDir = dirInfo;
var icon = CreateIcon(text);
icoTaskbar.Icon?.Dispose();
icoTaskbar.Icon = icon;
icoTaskbar.ToolTipText = dirInfo.Name;
icoTaskbar.Visibility = Visibility.Visible;
}
private void IconMenuItem_Click(object sender, EventArgs e)
{
if (sender is not MenuItem item) { return; }
if (currentDir == null) { return; }
if (item.Tag is not FileSystemInfo info) { return; }
try
{
info.Refresh();
if (!info.Exists) { throw new Exception($"路径已不存在 {info.FullName}"); }
OpenProcess(info.FullName);
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private static readonly Dictionary<string, BitmapSource> Icons = new();
private static BitmapSource? GetIcon(string f)
{
var ext = Path.GetExtension(f);
if (string.IsNullOrWhiteSpace(ext))
{
return null;
}
ext = ext.ToLower().Trim();
if (ext.Equals(".exe") || ext.Equals(".lnk"))
{
ext = f.ToLower().Trim();
}
if (Icons.TryGetValue(ext, out var result))
{
return result;
}
using var ico = System.Drawing.Icon.ExtractAssociatedIcon(f);
if (ico == null) { return null; }
var s = Imaging.CreateBitmapSourceFromHIcon(ico.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
Icons.Add(ext, s);
return s;
}
private void IconMenu_ContextMenuOpened(object sender, EventArgs e)
{
if (sender is not ContextMenu menu) { return; }
menu.Items.Clear();
if (currentDir == null) { return; }
if (!currentDir.Exists)
{
menu.Items.Add($"文件夹不存在 {currentDir.Name}");
menu.Items.Add(currentDir.FullName);
return;
}
var all = currentDir.EnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly);
foreach (var info in all)
{
var name = info.Name;
if (name.Length > 4 && name.EndsWith(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
name = name.Substring(0, name.Length - 4);
}
var item = new MenuItem
{
Header = name,
Tag = info
};
item.Click += IconMenuItem_Click;
var icoSource = info.FullName;
if (info.Attributes.HasFlag(FileAttributes.Directory))
{
icoSource = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe");
}
var ico = GetIcon(icoSource);
if (ico != null)
{
item.Icon = new System.Windows.Controls.Image() { Source = ico };
}
menu.Items.Add(item);
}
menu.Items.Add("");
}
#endregion
}
}