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(); } } } }