using Entries;
using NativeHelpers;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Management.Deployment;
namespace ShortcutUtil
{
public partial class MainForm : Form
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
if (!designMode)
{
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
}
return cp;
}
}
private EntryList entryList;
private Font defaultFont;
private Font nameFont;
private Brush fontBrush;
private AppResolver appResolver;
private EntryListItem listLayout;
private HelperLocation helperLocation;
private bool designMode;
public MainForm(EntryList entryList, AppResolver appResolver, HelperLocation helperLocation)
{
designMode = System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime;
this.helperLocation = helperLocation;
InitializeComponent();
typeof(ListBox).InvokeMember("DoubleBuffered",
BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, entryListBox, new object[] { true });
DoubleBuffered = true;
Text = entryList.FilePath == null ? "New shortcut file" : entryList.FilePath;
defaultFont = defaultShortcutLabel.Font;
nameFont = new Font(defaultFont, FontStyle.Bold);
fontBrush = new SolidBrush(defaultShortcutLabel.ForeColor);
this.entryList = entryList;
this.appResolver = appResolver;
entryListBox.Items.AddRange(this.entryList.Entries.ToArray());
if (this.entryList.Entries.Count > 0)
{
entryListBox.SelectedIndex = 0;
}
listLayout = new EntryListItem(entryListBox);
listLayout.TestButton.OnClick += ClickedTestButton;
helperLocationText.Text = helperLocation.Location;
UpdateHelperValidity();
}
private void UpdateHelperValidity()
{
bool valid = helperLocation.Valid;
helperLocationText.ForeColor = valid ? SystemColors.ControlText : Color.Red;
createButton.Enabled = valid && entryList.Entries.Count > 0;
}
private void ClickedTestButton(int index)
{
try
{
Entry entry = entryList.Entries[index];
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = entry.TargetExpanded,
Arguments = entry.ArgumentsExpanded,
UseShellExecute = true,
};
Process.Start(startInfo);
}
catch (Exception e)
{
MessageBox.Show("Couldn't start entry: " + e.ToString());
}
}
private Dictionary<Tuple<string, int, Size>, Icon> iconsByFileIndex = new Dictionary<Tuple<string, int, Size>, Icon>();
private Icon GetIcon(string file, int index, Size preferred)
{
Tuple<string, int, Size> key = new Tuple<string, int, Size>(file, index, preferred);
if (!iconsByFileIndex.ContainsKey(key))
{
Icon icon = null;
try
{
icon = new Icon(file, preferred);
}
catch (Exception)
{
icon = null;
}
if (icon == null)
{
try
{
icon = IconExtractor.Extract(file, index, true);
}
catch (Exception)
{
icon = null;
}
}
iconsByFileIndex.Add(key, icon);
/*
if (icon == null)
{
MessageBox.Show("Couldn't load icon " + index + " from " + file);
}
*/
}
return iconsByFileIndex[key];
}
private static readonly Size IconSize = new Size(64, 64);
private static readonly Size ItemPadding = new Size(6, 6);
private void entryListBox_DrawItem(object sender, DrawItemEventArgs e)
{
int index = e.Index;
//RectangleF baseRectF = new RectangleF(new PointF(), e.Bounds.Size);
Rectangle baseRect = new Rectangle(new Point(), e.Bounds.Size);
using (Bitmap b = new Bitmap(baseRect.Width, baseRect.Height))
{
Graphics g = Graphics.FromImage(b);
Brush backBrush = new SolidBrush(e.BackColor);
g.FillRectangle(backBrush, baseRect);
backBrush.Dispose();
if ((e.State & DrawItemState.Focus) == DrawItemState.Focus
&& (e.State & DrawItemState.NoFocusRect) != DrawItemState.NoFocusRect)
ControlPaint.DrawFocusRectangle(g, baseRect, ForeColor, BackColor);
listLayout.LayoutFromList();
if (index >= 0 && index < entryList.Entries.Count)
{
Rectangle iconBounds = new Rectangle(new Point(ItemPadding), IconSize);
Size textSize = new Size(0, nameFont.Height + 2);
Entry entry = entryList.Entries[index];
Icon icon = GetIcon(entry.Icon, entry.IconIndex, IconSize);
if (icon != null)
{
g.DrawIcon(icon, iconBounds);
}
PointF textLocation = new PointF(IconSize.Width + ItemPadding.Width * 2, ItemPadding.Width);
g.DrawString(index + ": " + entry.Name, nameFont, fontBrush, textLocation);
textLocation = PointF.Add(textLocation, textSize);
g.DrawString(entry.Target + " " + entry.Arguments, defaultFont, fontBrush, textLocation);
textLocation = PointF.Add(textLocation, textSize);
g.DrawString(entry.Description, defaultFont, fontBrush, textLocation);
textLocation = PointF.Add(textLocation, textSize);
listLayout.TestButton.RenderToItem(index, g);
}
e.Graphics.DrawImage(b, e.Bounds.Location);
}
}
private void entryListBox_MeasureItem(object sender, MeasureItemEventArgs e)
{
e.ItemHeight = GetItemSize().Height;
}
public Size GetItemSize()
{
return Size.Add(IconSize, new Size(0, ItemPadding.Height * 2));
}
private SearchForm search = new SearchForm();
private async void appButton_Click(object sender, EventArgs e)
{
appButton.Enabled = false;
PackageManager pm = new PackageManager();
List<Tuple<string, string>> options = new List<Tuple<string, string>>();
foreach (Package p in pm.FindPackagesForUser(string.Empty))
{
var apps = await p.GetAppListEntriesAsync().AsTask();
foreach (AppListEntry app in apps)
{
options.Add(new Tuple<string, string>(app.AppUserModelId, app.DisplayInfo.DisplayName + ": " + app.AppUserModelId));
}
}
string selectedAppUserModelId = search.GetSelection("Select UWP App", "Available Apps:", options);
if (selectedAppUserModelId != null)
{
appUserModelIdBox.Text = selectedAppUserModelId;
}
appButton.Enabled = true;
}
private static bool GetWindowHandle(IntPtr windowHandle, ref object windowHandles)
{
((ArrayList)windowHandles).Add(windowHandle);
return true;
}
private void hwndButton_Click(object sender, EventArgs e)
{
hwndButton.Enabled = false;
object handles = new ArrayList();
NativeCalls.EnumWindows(GetWindowHandle, ref handles);
List<Tuple<IntPtr, string, string>> titles = new List<Tuple<IntPtr, string, string>>();
foreach (object ptrObj in (ArrayList)handles)
{
IntPtr ptr = (IntPtr)ptrObj;
if (NativeCalls.IsAltTabWindow(ptr))
{
string title = NativeCalls.GetWindowTextManaged(ptr);
if (title != "")
{
/*
IPropertyStore store;
Guid guid = NativeValues.IID_IPropertyStore;
NativeCalls.VerifySucceeded((uint)NativeCalls.SHGetPropertyStoreForWindow(ptr, ref guid, out store));
using (PropVariant pv = new PropVariant())
{
NativeCalls.VerifySucceeded(store.GetValue(NativeValues.AppUserModelIDKey, pv));
string appUserModelId = pv.Value;
if (appUserModelId == null)
{
uint processId;
NativeCalls.GetWindowThreadProcessId(ptr, out processId);
IntPtr handle = NativeCalls.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, (int)processId);
try
{
appUserModelId = NativeCalls.GetApplicationUserModelIdManaged(handle);
}
catch (Exception) { }
}
}
*/
string appUserModelId = appResolver.GetAppIDForWindow(ptr);
if (appUserModelId == null)
{
uint processId;
NativeCalls.GetWindowThreadProcessId(ptr, out processId);
appUserModelId = appResolver.GetAppIDForProcess(processId);
}
if (appUserModelId != null)
{
titles.Add(new Tuple<IntPtr, string, string>(ptr, title, appUserModelId == null ? "NULL" : appUserModelId));
}
}
}
}
string selectedAppUserModelId = search.GetSelection("Select Window", "Available Windows:", titles.Select(t => new Tuple<string, string>(t.Item3, t.Item2 + ": " + t.Item3)).ToList());
if (selectedAppUserModelId != null)
{
appUserModelIdBox.Text = selectedAppUserModelId;
}
hwndButton.Enabled = true;
}
public static string EncodeParameterArgument(string original)
{
if (string.IsNullOrEmpty(original))
return original;
string value = Regex.Replace(original, @"(\\*)" + "\"", @"$1\$0");
value = Regex.Replace(value, @"^(.*\s.*?)(\\*)$", "\"$1$2$2\"", RegexOptions.Singleline);
return value;
}
private void createButton_Click(object sender, EventArgs e)
{
if (helperLocation.Valid && entryList.Entries.Count > 0)
{
int index = entryListBox.SelectedIndex;
if (index < 0 || index >= entryList.Entries.Count) index = 0;
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = Environment.CurrentDirectory;
sfd.Filter = "Shortcut (*.lnk)|*.lnk";
sfd.Title = "Select output file";
sfd.DefaultExt = "lnk";
sfd.CheckPathExists = true;
sfd.CreatePrompt = false;
sfd.OverwritePrompt = true;
DialogResult res = sfd.ShowDialog();
if (res == DialogResult.OK)
{
Entry selected = entryList.Entries[index];
ShellLink shellLink = new ShellLink();
shellLink.TargetPath = helperLocation.Location;
shellLink.Arguments = String.Join(" ",
new string[]
{
"-s", entryList.FilePath, "-i", "" + index, "-a", appUserModelIdBox.Text
}.Select(a => EncodeParameterArgument(a)));
shellLink.Description = selected.Description;
shellLink.IconLocation = new Tuple<string, int>(selected.Icon, selected.IconIndex);
shellLink.WorkingDirectory = Path.GetDirectoryName(entryList.FilePath);
shellLink.AppUserModelID = appUserModelIdBox.Text;
shellLink.Save(sfd.FileName);
}
}
}
private void helperLocationText_TextChanged(object sender, EventArgs e)
{
helperLocation.Location = helperLocationText.Text;
UpdateHelperValidity();
}
private void helperLocationButton_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Executables (*.exe)|*.exe";
ofd.InitialDirectory = Path.GetDirectoryName(helperLocation.Location);
ofd.Title = "Select helper executable";
ofd.DefaultExt = "exe";
ofd.Multiselect = false;
ofd.CheckFileExists = true;
DialogResult result = ofd.ShowDialog();
if (result == DialogResult.OK)
{
helperLocation.Location = ofd.FileName;
helperLocationText.Text = helperLocation.Location;
UpdateHelperValidity();
}
}
}
}