2020-07-07 07:15:45 +12:00
|
|
|
|
// <copyright file="RowData.cs" company="PlaceholderCompany">
|
|
|
|
|
// Copyright (c) PlaceholderCompany. All rights reserved.
|
|
|
|
|
// </copyright>
|
2020-03-28 08:43:16 +13:00
|
|
|
|
|
|
|
|
|
namespace SystemTrayMenu.DataClasses
|
|
|
|
|
{
|
2020-07-07 07:15:45 +12:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Security;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows.Forms;
|
2020-07-08 03:05:19 +12:00
|
|
|
|
using IWshRuntimeLibrary;
|
2020-07-07 07:15:45 +12:00
|
|
|
|
using SystemTrayMenu.Utilities;
|
|
|
|
|
using TAFactory.IconPack;
|
|
|
|
|
using Menu = SystemTrayMenu.UserInterface.Menu;
|
|
|
|
|
|
2020-03-30 06:26:45 +13:00
|
|
|
|
internal class RowData : IDisposable
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
private static DateTime contextMenuClosed;
|
|
|
|
|
private string workingDirectory;
|
|
|
|
|
private string arguments;
|
|
|
|
|
private string text;
|
|
|
|
|
private Icon icon = null;
|
2020-03-30 12:19:11 +13:00
|
|
|
|
private bool diposeIcon = true;
|
2020-03-28 08:43:16 +13:00
|
|
|
|
private bool isDisposed = false;
|
|
|
|
|
|
2020-03-30 06:26:45 +13:00
|
|
|
|
internal RowData()
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-08 03:05:19 +12:00
|
|
|
|
internal FileInfo FileInfo { get; set; }
|
|
|
|
|
|
|
|
|
|
internal Menu SubMenu { get; set; }
|
|
|
|
|
|
|
|
|
|
internal bool IsMenuOpen { get; set; }
|
|
|
|
|
|
|
|
|
|
internal bool IsSelected { get; set; }
|
|
|
|
|
|
|
|
|
|
internal bool ContainsMenu { get; set; }
|
|
|
|
|
|
|
|
|
|
internal bool IsContextMenuOpen { get; set; }
|
|
|
|
|
|
|
|
|
|
internal bool IsResolvedLnk { get; set; }
|
|
|
|
|
|
|
|
|
|
internal bool HiddenEntry { get; set; }
|
|
|
|
|
|
|
|
|
|
internal string TargetFilePath { get; set; }
|
|
|
|
|
|
|
|
|
|
internal string TargetFilePathOrig { get; set; }
|
|
|
|
|
|
|
|
|
|
internal int RowIndex { get; set; }
|
|
|
|
|
|
|
|
|
|
internal int MenuLevel { get; set; }
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-30 06:26:45 +13:00
|
|
|
|
internal void SetText(string text)
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
this.text = text;
|
2020-03-28 08:43:16 +13:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 05:14:51 +12:00
|
|
|
|
internal void SetData(RowData data, DataTable dataTable)
|
2020-03-30 06:26:45 +13:00
|
|
|
|
{
|
2020-05-14 05:14:51 +12:00
|
|
|
|
DataRow row = dataTable.Rows.Add();
|
|
|
|
|
data.RowIndex = dataTable.Rows.IndexOf(row);
|
2020-03-30 06:26:45 +13:00
|
|
|
|
|
2020-07-07 09:37:55 +12:00
|
|
|
|
if (icon == null)
|
2020-03-30 06:26:45 +13:00
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon = Properties.Resources.WhiteTransparency;
|
2020-03-30 06:26:45 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (HiddenEntry)
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
row[0] = IconReader.AddIconOverlay(
|
|
|
|
|
data.icon,
|
2020-03-30 06:26:45 +13:00
|
|
|
|
Properties.Resources.WhiteTransparency);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
row[0] = data.icon;
|
2020-03-30 06:26:45 +13:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-07 09:37:55 +12:00
|
|
|
|
row[1] = data.text;
|
2020-05-14 05:14:51 +12:00
|
|
|
|
row[2] = data;
|
2020-03-30 06:26:45 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal bool ReadIcon(bool isDirectory, ref string resolvedLnkPath)
|
|
|
|
|
{
|
|
|
|
|
bool isLnkDirectory = false;
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(TargetFilePath))
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"TargetFilePath from {resolvedLnkPath} empty");
|
|
|
|
|
}
|
|
|
|
|
else if (isDirectory)
|
|
|
|
|
{
|
2020-07-27 08:36:31 +12:00
|
|
|
|
icon = IconReader.GetFolderIconSTA(
|
2020-07-07 07:15:45 +12:00
|
|
|
|
TargetFilePath,
|
|
|
|
|
IconReader.FolderType.Closed,
|
|
|
|
|
false);
|
2020-03-30 06:26:45 +13:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
string fileExtension = Path.GetExtension(TargetFilePath);
|
|
|
|
|
|
|
|
|
|
if (fileExtension == ".lnk")
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
handled = SetLnk(
|
|
|
|
|
ref isLnkDirectory,
|
2020-03-30 06:26:45 +13:00
|
|
|
|
ref resolvedLnkPath);
|
|
|
|
|
}
|
|
|
|
|
else if (fileExtension == ".url")
|
|
|
|
|
{
|
|
|
|
|
handled = SetUrl();
|
|
|
|
|
}
|
|
|
|
|
else if (fileExtension == ".sln")
|
|
|
|
|
{
|
|
|
|
|
handled = SetSln();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!handled)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon = IconReader.GetFileIconWithCache(TargetFilePath, false);
|
2020-03-30 12:19:11 +13:00
|
|
|
|
diposeIcon = false;
|
2020-03-30 06:26:45 +13:00
|
|
|
|
|
|
|
|
|
// other project -> fails sometimes
|
2020-07-07 07:15:45 +12:00
|
|
|
|
// icon = IconHelper.ExtractIcon(TargetFilePath, 0);
|
2020-03-30 06:26:45 +13:00
|
|
|
|
|
|
|
|
|
// standard way -> fails sometimes
|
2020-07-07 07:15:45 +12:00
|
|
|
|
// icon = Icon.ExtractAssociatedIcon(filePath);
|
2020-03-30 06:26:45 +13:00
|
|
|
|
|
|
|
|
|
// API Code Pack -> fails sometimes
|
2020-07-07 07:15:45 +12:00
|
|
|
|
// ShellFile shellFile = ShellFile.FromFilePath(filePath);
|
|
|
|
|
// Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;
|
2020-03-30 06:26:45 +13:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
if (ex is SecurityException ||
|
|
|
|
|
ex is ArgumentException ||
|
|
|
|
|
ex is UnauthorizedAccessException ||
|
|
|
|
|
ex is PathTooLongException ||
|
|
|
|
|
ex is NotSupportedException)
|
|
|
|
|
{
|
|
|
|
|
Log.Warn($"path:'{TargetFilePath}'", ex);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isLnkDirectory;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-07 07:15:45 +12:00
|
|
|
|
internal void MouseDown(DataGridView dgv, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e != null &&
|
|
|
|
|
e.Button == MouseButtons.Right &&
|
|
|
|
|
FileInfo != null &&
|
|
|
|
|
dgv != null &&
|
|
|
|
|
dgv.Rows.Count > RowIndex &&
|
2020-07-07 09:37:55 +12:00
|
|
|
|
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
|
2020-07-07 07:15:45 +12:00
|
|
|
|
{
|
|
|
|
|
IsContextMenuOpen = true;
|
|
|
|
|
|
|
|
|
|
ShellContextMenu ctxMnu = new ShellContextMenu();
|
|
|
|
|
Point location = dgv.FindForm().Location;
|
|
|
|
|
Point point = new Point(
|
|
|
|
|
e.X + location.X + dgv.Location.X,
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IsContextMenuOpen = false;
|
2020-07-07 09:37:55 +12:00
|
|
|
|
contextMenuClosed = DateTime.Now;
|
2020-07-07 07:15:45 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void DoubleClick(MouseEventArgs e)
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
if (!ContainsMenu &&
|
|
|
|
|
(e == null || e.Button == MouseButtons.Left))
|
2020-07-07 07:15:45 +12:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using Process p = new Process
|
|
|
|
|
{
|
|
|
|
|
StartInfo = new ProcessStartInfo(TargetFilePath)
|
|
|
|
|
{
|
|
|
|
|
FileName = TargetFilePathOrig,
|
2020-07-07 09:37:55 +12:00
|
|
|
|
Arguments = arguments,
|
|
|
|
|
WorkingDirectory = workingDirectory,
|
2020-07-07 07:15:45 +12:00
|
|
|
|
CreateNoWindow = true,
|
|
|
|
|
UseShellExecute = true,
|
2020-07-07 09:37:55 +12:00
|
|
|
|
},
|
2020-07-07 07:15:45 +12:00
|
|
|
|
};
|
|
|
|
|
p.Start();
|
|
|
|
|
}
|
|
|
|
|
catch (Win32Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Warn($"path:'{TargetFilePath}'", ex);
|
|
|
|
|
MessageBox.Show(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-07 09:37:55 +12:00
|
|
|
|
if (ContainsMenu &&
|
|
|
|
|
(e == null || e.Button == MouseButtons.Left))
|
2020-07-07 07:15:45 +12:00
|
|
|
|
{
|
2020-07-16 22:42:00 +12:00
|
|
|
|
Log.ProcessStart("explorer.exe", TargetFilePath, true);
|
2020-07-07 07:15:45 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (!isDisposed)
|
|
|
|
|
{
|
|
|
|
|
if (diposeIcon)
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon?.Dispose();
|
2020-07-07 07:15:45 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isDisposed = true;
|
|
|
|
|
}
|
2020-03-30 06:26:45 +13:00
|
|
|
|
|
2020-07-07 09:37:55 +12:00
|
|
|
|
private bool SetLnk(
|
|
|
|
|
ref bool isLnkDirectory,
|
2020-03-28 08:43:16 +13:00
|
|
|
|
ref string resolvedLnkPath)
|
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
2020-07-07 07:15:45 +12:00
|
|
|
|
resolvedLnkPath = FileLnk.GetResolvedFileName(TargetFilePath);
|
|
|
|
|
if (FileLnk.IsDirectory(resolvedLnkPath))
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
2020-07-27 08:36:31 +12:00
|
|
|
|
icon = IconReader.GetFolderIconSTA(TargetFilePath, IconReader.FolderType.Open, true);
|
2020-03-28 08:43:16 +13:00
|
|
|
|
handled = true;
|
|
|
|
|
isLnkDirectory = true;
|
|
|
|
|
}
|
2020-07-07 07:15:45 +12:00
|
|
|
|
else if (FileLnk.IsNetworkRoot(resolvedLnkPath))
|
2020-07-05 07:20:56 +12:00
|
|
|
|
{
|
|
|
|
|
isLnkDirectory = true;
|
|
|
|
|
}
|
2020-03-28 08:43:16 +13:00
|
|
|
|
else if (string.IsNullOrEmpty(resolvedLnkPath))
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"Resolve *.LNK '{TargetFilePath}' has no icon");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
IWshShell shell = new WshShell();
|
|
|
|
|
IWshShortcut lnk = shell.CreateShortcut(TargetFilePath)
|
|
|
|
|
as IWshShortcut;
|
2020-07-07 09:37:55 +12:00
|
|
|
|
arguments = lnk.Arguments;
|
|
|
|
|
workingDirectory = lnk.WorkingDirectory;
|
2020-03-28 08:43:16 +13:00
|
|
|
|
string iconLocation = lnk.IconLocation;
|
|
|
|
|
if (iconLocation.Length > 2)
|
|
|
|
|
{
|
2020-07-07 02:46:47 +12:00
|
|
|
|
iconLocation = iconLocation[0..^2];
|
2020-03-28 08:43:16 +13:00
|
|
|
|
if (System.IO.File.Exists(iconLocation))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon = Icon.ExtractAssociatedIcon(iconLocation);
|
2020-03-28 08:43:16 +13:00
|
|
|
|
handled = true;
|
|
|
|
|
}
|
2020-03-30 06:26:45 +13:00
|
|
|
|
catch (ArgumentException ex)
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
2020-04-16 03:23:42 +12:00
|
|
|
|
Log.Warn($"iconLocation:'{iconLocation}'", ex);
|
2020-03-28 08:43:16 +13:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetFilePath = resolvedLnkPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetText(Path.GetFileNameWithoutExtension(TargetFilePathOrig));
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool SetUrl()
|
|
|
|
|
{
|
|
|
|
|
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))
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"Resolve *.URL '{TargetFilePath}'" +
|
|
|
|
|
$"No default browser found!");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon = IconReader.GetFileIconWithCache(browserPath, false);
|
2020-03-30 12:19:11 +13:00
|
|
|
|
diposeIcon = false;
|
2020-03-28 08:43:16 +13:00
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (System.IO.File.Exists(iconFile))
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon = Icon.ExtractAssociatedIcon(iconFile);
|
2020-03-28 08:43:16 +13:00
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"Resolve *.URL '{TargetFilePath}' has no icon");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-03-30 06:26:45 +13:00
|
|
|
|
if (ex is SecurityException ||
|
|
|
|
|
ex is ArgumentException ||
|
|
|
|
|
ex is UnauthorizedAccessException ||
|
|
|
|
|
ex is PathTooLongException ||
|
|
|
|
|
ex is NotSupportedException)
|
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
Log.Warn(
|
|
|
|
|
$"path:'{TargetFilePath}', " +
|
2020-03-30 06:26:45 +13:00
|
|
|
|
$"iconFile:'{iconFile}'", ex);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2020-03-28 08:43:16 +13:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-07 02:46:47 +12:00
|
|
|
|
SetText($"{FileInfo.Name[0..^4]}");
|
2020-03-28 08:43:16 +13:00
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool SetSln()
|
|
|
|
|
{
|
|
|
|
|
bool handled = false;
|
|
|
|
|
StringBuilder executable = new StringBuilder(1024);
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-03-30 06:26:45 +13:00
|
|
|
|
DllImports.NativeMethods.Shell32FindExecutable(TargetFilePath, string.Empty, executable);
|
2020-07-07 09:37:55 +12:00
|
|
|
|
|
2020-03-28 08:43:16 +13:00
|
|
|
|
// icon = IconReader.GetFileIcon(executable, false);
|
|
|
|
|
// e.g. VS 2019 icon, need another icom in imagelist
|
|
|
|
|
List<Icon> extractedIcons = IconHelper.ExtractAllIcons(
|
|
|
|
|
executable.ToString());
|
2020-07-07 09:37:55 +12:00
|
|
|
|
icon = extractedIcons.Last();
|
2020-03-28 08:43:16 +13:00
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-03-30 06:26:45 +13:00
|
|
|
|
if (ex is SecurityException ||
|
|
|
|
|
ex is ArgumentException ||
|
|
|
|
|
ex is UnauthorizedAccessException ||
|
|
|
|
|
ex is PathTooLongException ||
|
|
|
|
|
ex is NotSupportedException)
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
2020-07-07 09:37:55 +12:00
|
|
|
|
Log.Warn(
|
|
|
|
|
$"path:'{TargetFilePath}', " +
|
2020-03-30 06:26:45 +13:00
|
|
|
|
$"executable:'{executable}'", ex);
|
2020-03-28 08:43:16 +13:00
|
|
|
|
}
|
2020-03-30 06:26:45 +13:00
|
|
|
|
else
|
2020-03-28 08:43:16 +13:00
|
|
|
|
{
|
2020-03-30 06:26:45 +13:00
|
|
|
|
throw;
|
2020-03-28 08:43:16 +13:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-30 06:26:45 +13:00
|
|
|
|
return handled;
|
2020-03-28 08:43:16 +13:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|