2020-03-17 02:45:19 +13:00
|
|
|
|
using IWshRuntimeLibrary;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows.Forms;
|
2020-03-09 01:21:15 +13:00
|
|
|
|
using SystemTrayMenu.Handler;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
using SystemTrayMenu.Helper;
|
|
|
|
|
using TAFactory.IconPack;
|
|
|
|
|
|
|
|
|
|
namespace SystemTrayMenu.Controls
|
|
|
|
|
{
|
|
|
|
|
public class RowData : IDisposable
|
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public event Action<object, EventArgs> OpenMenu;
|
|
|
|
|
public BackgroundWorker Reading = new BackgroundWorker();
|
2019-08-03 19:27:33 +12:00
|
|
|
|
public FileInfo FileInfo;
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public Menu SubMenu;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
public Icon Icon;
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public bool IsSelected;
|
|
|
|
|
public bool IsSelectedByKeyboard;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
public bool ContainsMenu;
|
|
|
|
|
public bool IsContextMenuOpen;
|
|
|
|
|
public bool ResolvedFileNotFound;
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public bool IsResolvedLnk;
|
|
|
|
|
public bool IsLoading = false;
|
|
|
|
|
public bool RestartLoading = false;
|
|
|
|
|
public bool HiddenEntry;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
public string WorkingDirectory;
|
|
|
|
|
public string Arguments;
|
|
|
|
|
public string TargetFilePath;
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public string TargetFilePathOrig;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
public string Text;
|
|
|
|
|
public int RowIndex;
|
2020-03-24 00:32:47 +13:00
|
|
|
|
private WaitMenuOpen waitMenuOpen = new WaitMenuOpen();
|
|
|
|
|
private Icon icon = null;
|
|
|
|
|
private bool isDisposed = false;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public RowData()
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
Reading.WorkerSupportsCancellation = true;
|
|
|
|
|
waitMenuOpen.DoOpen += WaitMenuOpen_DoOpen;
|
|
|
|
|
}
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public void SetText(string text)
|
|
|
|
|
{
|
2020-03-24 00:22:26 +13:00
|
|
|
|
if (text != null && text.Length > MenuDefines.LengthMax)
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
text = $"{text.Substring(0, MenuDefines.LengthMax)}...";
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
2020-03-23 01:36:54 +13:00
|
|
|
|
Text = text;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 02:45:19 +13:00
|
|
|
|
private bool SetLnk(ref bool isLnkDirectory,
|
2019-08-03 19:27:33 +12:00
|
|
|
|
ref string resolvedLnkPath)
|
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
resolvedLnkPath = LnkHelper.ResolveShortcut(TargetFilePath);
|
|
|
|
|
if (LnkHelper.IsDirectory(resolvedLnkPath))
|
|
|
|
|
{
|
|
|
|
|
Icon = IconReader.GetFolderIcon(TargetFilePath,
|
|
|
|
|
IconReader.FolderType.Open, true);
|
|
|
|
|
handled = true;
|
|
|
|
|
isLnkDirectory = true;
|
|
|
|
|
}
|
|
|
|
|
else if (string.IsNullOrEmpty(resolvedLnkPath))
|
|
|
|
|
{
|
|
|
|
|
ResolvedFileNotFound = true;
|
2020-03-17 03:57:51 +13:00
|
|
|
|
Log.Info($"Resolve *.LNK '{TargetFilePath}' has no icon");
|
2020-03-17 02:45:19 +13:00
|
|
|
|
#warning [Feature] Resolve network root #48, start here
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
IWshShell shell = new WshShell();
|
|
|
|
|
var lnk = shell.CreateShortcut(TargetFilePath)
|
|
|
|
|
as IWshShortcut;
|
|
|
|
|
Arguments = lnk.Arguments;
|
|
|
|
|
WorkingDirectory = lnk.WorkingDirectory;
|
|
|
|
|
string iconLocation = lnk.IconLocation;
|
|
|
|
|
if (iconLocation.Length > 2)
|
|
|
|
|
{
|
|
|
|
|
iconLocation = iconLocation.Substring(0,
|
|
|
|
|
iconLocation.Length - 2);
|
|
|
|
|
if (System.IO.File.Exists(iconLocation))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Icon = Icon.ExtractAssociatedIcon(iconLocation);
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-03-17 02:45:19 +13:00
|
|
|
|
Log.Error($"iconLocation:'{iconLocation}'", ex);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetFilePath = resolvedLnkPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetText(Path.GetFileNameWithoutExtension(TargetFilePathOrig));
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 02:45:19 +13:00
|
|
|
|
private bool SetUrl()
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
string iconFile = string.Empty;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
FileIni file = new FileIni(TargetFilePath);
|
|
|
|
|
iconFile = file.Value("IconFile", string.Empty);
|
|
|
|
|
if (string.IsNullOrEmpty(iconFile))
|
|
|
|
|
{
|
|
|
|
|
string browserPath = FileUrl.GetDefaultBrowserPath();
|
|
|
|
|
if (string.IsNullOrEmpty(browserPath))
|
|
|
|
|
{
|
2020-03-24 00:22:26 +13:00
|
|
|
|
Log.Info($"Resolve *.URL '{TargetFilePath}'" +
|
|
|
|
|
$"No default browser found!");
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-03-15 22:27:05 +13:00
|
|
|
|
Icon = IconReader.GetFileIconWithCache(browserPath, false);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (System.IO.File.Exists(iconFile))
|
|
|
|
|
{
|
|
|
|
|
Icon = Icon.ExtractAssociatedIcon(iconFile);
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-03-17 03:57:51 +13:00
|
|
|
|
Log.Info($"Resolve *.URL '{TargetFilePath}' has no icon");
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-03-17 02:45:19 +13:00
|
|
|
|
Log.Error($"TargetFilePath:'{TargetFilePath}', " +
|
|
|
|
|
$"iconFile:'{iconFile}'", ex);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetText($"{FileInfo.Name.Substring(0, FileInfo.Name.Length - 4)}");
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-23 01:14:11 +13:00
|
|
|
|
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
|
2020-03-24 00:32:47 +13:00
|
|
|
|
private static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult);
|
2020-03-17 02:45:19 +13:00
|
|
|
|
private bool SetSln()
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
var executable = new StringBuilder(1024);
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-03-24 00:22:26 +13:00
|
|
|
|
_ = FindExecutable(TargetFilePath, string.Empty, executable);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
// icon = IconReader.GetFileIcon(executable, false);
|
|
|
|
|
// e.g. VS 2019 icon, need another icom in imagelist
|
|
|
|
|
List<Icon> extractedIcons = IconHelper.ExtractAllIcons(
|
|
|
|
|
executable.ToString());
|
|
|
|
|
Icon = extractedIcons.Last();
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-03-17 02:45:19 +13:00
|
|
|
|
Log.Error($"TargetFilePath:'{TargetFilePath}', " +
|
2020-03-23 01:36:54 +13:00
|
|
|
|
$"executable:'{executable.ToString()}'", ex);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public void SetData(RowData data, DataGridView dgv)
|
|
|
|
|
{
|
|
|
|
|
data.RowIndex = dgv.Rows.Add();
|
|
|
|
|
DataGridViewRow row = dgv.Rows[data.RowIndex];
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
if (Icon == null)
|
|
|
|
|
{
|
|
|
|
|
Icon = Properties.Resources.SystemTrayMenu;
|
|
|
|
|
}
|
|
|
|
|
DataGridViewImageCell cellIcon =
|
|
|
|
|
(DataGridViewImageCell)row.Cells[0];
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
if (HiddenEntry)
|
|
|
|
|
{
|
|
|
|
|
cellIcon.Value = IconReader.AddIconOverlay(data.Icon,
|
|
|
|
|
Properties.Resources.WhiteTransparency);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cellIcon.Value = data.Icon;
|
|
|
|
|
}
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
DataGridViewTextBoxCell cellName =
|
|
|
|
|
(DataGridViewTextBoxCell)row.Cells[1];
|
|
|
|
|
cellName.Value = data.Text;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
row.Tag = data;
|
|
|
|
|
}
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public bool ReadIcon(bool isDirectory, ref string resolvedLnkPath)
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
bool isLnkDirectory = false;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
if (string.IsNullOrEmpty(TargetFilePath))
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
Log.Info($"TargetFilePath from {resolvedLnkPath} empty");
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
2020-03-23 01:36:54 +13:00
|
|
|
|
else if (isDirectory)
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
Icon = IconReader.GetFolderIcon(TargetFilePath,
|
|
|
|
|
IconReader.FolderType.Closed, false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
string fileExtension = Path.GetExtension(TargetFilePath);
|
|
|
|
|
|
|
|
|
|
if (fileExtension == ".lnk")
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
handled = SetLnk(ref isLnkDirectory,
|
|
|
|
|
ref resolvedLnkPath);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
2020-03-23 01:36:54 +13:00
|
|
|
|
else if (fileExtension == ".url")
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
2020-03-23 01:36:54 +13:00
|
|
|
|
handled = SetUrl();
|
|
|
|
|
}
|
|
|
|
|
else if (fileExtension == ".sln")
|
|
|
|
|
{
|
|
|
|
|
handled = SetSln();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!handled)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Icon = IconReader.GetFileIconWithCache(TargetFilePath, false);
|
|
|
|
|
|
|
|
|
|
// other project -> fails sometimes
|
|
|
|
|
//icon = IconHelper.ExtractIcon(TargetFilePath, 0);
|
|
|
|
|
|
|
|
|
|
// standard way -> fails sometimes
|
|
|
|
|
//icon = Icon.ExtractAssociatedIcon(filePath);
|
|
|
|
|
|
|
|
|
|
// API Code Pack -> fails sometimes
|
|
|
|
|
//ShellFile shellFile = ShellFile.FromFilePath(filePath);
|
|
|
|
|
//Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error($"TargetFilePath:'{TargetFilePath}'", ex);
|
|
|
|
|
}
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-23 01:36:54 +13:00
|
|
|
|
|
|
|
|
|
return isLnkDirectory;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void MouseDown(DataGridView dgv, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (ContainsMenu)
|
|
|
|
|
{
|
|
|
|
|
TriggerMenuOpener(); // Touchscreen
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsLoading)
|
|
|
|
|
{
|
|
|
|
|
waitMenuOpen.Click();
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-19 08:11:55 +13:00
|
|
|
|
if (e == null ||
|
2019-08-03 19:27:33 +12:00
|
|
|
|
e.Button == MouseButtons.Left &&
|
|
|
|
|
!ContainsMenu)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//https://stackoverflow.com/questions/31627801/
|
|
|
|
|
Process p = new Process();
|
|
|
|
|
p.StartInfo = new ProcessStartInfo(TargetFilePath);
|
|
|
|
|
p.StartInfo.Arguments = Arguments;
|
|
|
|
|
p.StartInfo.WorkingDirectory = WorkingDirectory;
|
|
|
|
|
p.StartInfo.CreateNoWindow = true;
|
|
|
|
|
p.Start();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-03-17 02:45:19 +13:00
|
|
|
|
Log.Error($"TargetFilePath:'{ TargetFilePath}', " +
|
|
|
|
|
$"=>FileNotFound?", ex);
|
2019-08-03 19:27:33 +12:00
|
|
|
|
MessageBox.Show(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e != null &&
|
|
|
|
|
e.Button == MouseButtons.Right &&
|
|
|
|
|
FileInfo != null &&
|
|
|
|
|
dgv.Rows.Count > RowIndex)
|
|
|
|
|
{
|
|
|
|
|
IsContextMenuOpen = true;
|
|
|
|
|
IsSelected = true;
|
|
|
|
|
dgv.Rows[RowIndex].Selected = true;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ShellContextMenu ctxMnu = new ShellContextMenu();
|
|
|
|
|
Point location = dgv.FindForm().Location;
|
|
|
|
|
Point point = new Point(
|
2019-11-19 08:11:55 +13:00
|
|
|
|
e.X + location.X + dgv.Location.X,
|
2019-08-03 19:27:33 +12:00
|
|
|
|
e.Y + location.Y + dgv.Location.Y);
|
|
|
|
|
if (ContainsMenu)
|
|
|
|
|
{
|
|
|
|
|
DirectoryInfo[] dir = new DirectoryInfo[1];
|
|
|
|
|
dir[0] = new DirectoryInfo(TargetFilePathOrig);
|
|
|
|
|
ctxMnu.ShowContextMenu(dir, point);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FileInfo[] arrFI = new FileInfo[1];
|
|
|
|
|
arrFI[0] = new FileInfo(TargetFilePathOrig);
|
|
|
|
|
ctxMnu.ShowContextMenu(arrFI, point);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(ex.ToString() + TargetFilePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dgv.IsDisposed)
|
|
|
|
|
{
|
|
|
|
|
IsSelected = false;
|
|
|
|
|
dgv.Rows[RowIndex].Selected = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IsContextMenuOpen = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-23 01:36:54 +13:00
|
|
|
|
public void DoubleClick()
|
|
|
|
|
{
|
|
|
|
|
if (ContainsMenu)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Process.Start("explorer.exe", TargetFilePath);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error($"TargetFilePath:'{TargetFilePath}', " +
|
|
|
|
|
$"=>DirectoryNotFound?", ex);
|
|
|
|
|
ex = new DirectoryNotFoundException();
|
|
|
|
|
MessageBox.Show(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-03 19:27:33 +12:00
|
|
|
|
public void MenuLoaded()
|
|
|
|
|
{
|
|
|
|
|
waitMenuOpen.MenuLoaded();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StartMenuOpener()
|
|
|
|
|
{
|
|
|
|
|
if (ContainsMenu)
|
|
|
|
|
{
|
|
|
|
|
IsLoading = true;
|
|
|
|
|
waitMenuOpen.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerMenuOpener()
|
|
|
|
|
{
|
|
|
|
|
if (ContainsMenu && IsLoading)
|
|
|
|
|
{
|
|
|
|
|
waitMenuOpen.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StopLoadMenuAndStartWaitToOpenIt()
|
|
|
|
|
{
|
|
|
|
|
if (ContainsMenu)
|
|
|
|
|
{
|
|
|
|
|
waitMenuOpen.Stop();
|
|
|
|
|
//IsLoading = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void WaitMenuOpen_DoOpen()
|
|
|
|
|
{
|
|
|
|
|
IsLoading = false;
|
|
|
|
|
OpenMenu?.Invoke(this, null);
|
2020-03-24 00:24:16 +13:00
|
|
|
|
}
|
2019-08-03 19:27:33 +12:00
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2020-03-23 01:14:11 +13:00
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (!isDisposed)
|
2019-08-03 19:27:33 +12:00
|
|
|
|
{
|
|
|
|
|
icon?.Dispose();
|
|
|
|
|
waitMenuOpen.Dispose();
|
|
|
|
|
}
|
2020-03-23 01:14:11 +13:00
|
|
|
|
isDisposed = true;
|
2019-08-03 19:27:33 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|