diff --git a/ShortPATH.sln b/ShortPATH.sln
new file mode 100644
index 0000000..7ab0b6d
--- /dev/null
+++ b/ShortPATH.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2042
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShortPATH", "ShortPATH\ShortPATH.csproj", "{A63270E0-85CD-4201-94A8-54802601CF7E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A63270E0-85CD-4201-94A8-54802601CF7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A63270E0-85CD-4201-94A8-54802601CF7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A63270E0-85CD-4201-94A8-54802601CF7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A63270E0-85CD-4201-94A8-54802601CF7E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {54087D54-133B-4375-A6E1-C589CE3FDCD7}
+ EndGlobalSection
+EndGlobal
diff --git a/ShortPATH/App.config b/ShortPATH/App.config
new file mode 100644
index 0000000..731f6de
--- /dev/null
+++ b/ShortPATH/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ShortPATH/Form1.Designer.cs b/ShortPATH/Form1.Designer.cs
new file mode 100644
index 0000000..63b3865
--- /dev/null
+++ b/ShortPATH/Form1.Designer.cs
@@ -0,0 +1,184 @@
+namespace ShortPATH
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.listBox1 = new System.Windows.Forms.ListBox();
+ this.button1 = new System.Windows.Forms.Button();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.textBox2 = new System.Windows.Forms.TextBox();
+ this.button2 = new System.Windows.Forms.Button();
+ this.button3 = new System.Windows.Forms.Button();
+ this.button4 = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // listBox1
+ //
+ this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)));
+ this.listBox1.Font = new System.Drawing.Font("Calibri", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.listBox1.FormattingEnabled = true;
+ this.listBox1.ItemHeight = 14;
+ this.listBox1.Location = new System.Drawing.Point(10, 12);
+ this.listBox1.Name = "listBox1";
+ this.listBox1.Size = new System.Drawing.Size(132, 130);
+ this.listBox1.TabIndex = 0;
+ this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
+ //
+ // button1
+ //
+ this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.button1.Location = new System.Drawing.Point(10, 154);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(132, 38);
+ this.button1.TabIndex = 1;
+ this.button1.Text = "Add";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // textBox1
+ //
+ this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.textBox1.Enabled = false;
+ this.textBox1.Font = new System.Drawing.Font("Calibri", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textBox1.Location = new System.Drawing.Point(152, 36);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(321, 22);
+ this.textBox1.TabIndex = 2;
+ this.textBox1.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBox1_KeyUp);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Font = new System.Drawing.Font("Calibri", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.Location = new System.Drawing.Point(154, 17);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(54, 14);
+ this.label1.TabIndex = 3;
+ this.label1.Text = "Shortcut:";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Font = new System.Drawing.Font("Calibri", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.Location = new System.Drawing.Point(154, 75);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(45, 14);
+ this.label2.TabIndex = 5;
+ this.label2.Text = "Folder:";
+ //
+ // textBox2
+ //
+ this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.textBox2.Enabled = false;
+ this.textBox2.Font = new System.Drawing.Font("Calibri", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textBox2.Location = new System.Drawing.Point(152, 94);
+ this.textBox2.Name = "textBox2";
+ this.textBox2.Size = new System.Drawing.Size(285, 22);
+ this.textBox2.TabIndex = 4;
+ this.textBox2.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBox2_KeyUp);
+ //
+ // button2
+ //
+ this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.button2.Enabled = false;
+ this.button2.Location = new System.Drawing.Point(443, 93);
+ this.button2.Name = "button2";
+ this.button2.Size = new System.Drawing.Size(30, 24);
+ this.button2.TabIndex = 6;
+ this.button2.Text = "...";
+ this.button2.UseVisualStyleBackColor = true;
+ this.button2.Click += new System.EventHandler(this.button2_Click);
+ //
+ // button3
+ //
+ this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.button3.Enabled = false;
+ this.button3.Location = new System.Drawing.Point(341, 154);
+ this.button3.Name = "button3";
+ this.button3.Size = new System.Drawing.Size(132, 38);
+ this.button3.TabIndex = 7;
+ this.button3.Text = "Save";
+ this.button3.UseVisualStyleBackColor = true;
+ this.button3.Click += new System.EventHandler(this.button3_Click);
+ //
+ // button4
+ //
+ this.button4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.button4.Enabled = false;
+ this.button4.Location = new System.Drawing.Point(203, 154);
+ this.button4.Name = "button4";
+ this.button4.Size = new System.Drawing.Size(132, 38);
+ this.button4.TabIndex = 8;
+ this.button4.Text = "Remove";
+ this.button4.UseVisualStyleBackColor = true;
+ this.button4.Click += new System.EventHandler(this.button4_Click);
+ //
+ // Form1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(484, 201);
+ this.Controls.Add(this.button4);
+ this.Controls.Add(this.button3);
+ this.Controls.Add(this.button2);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.textBox2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.textBox1);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.listBox1);
+ this.MinimumSize = new System.Drawing.Size(450, 230);
+ this.Name = "Form1";
+ this.ShowIcon = false;
+ this.Text = "ShortPATH";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.ListBox listBox1;
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox textBox2;
+ private System.Windows.Forms.Button button2;
+ private System.Windows.Forms.Button button3;
+ private System.Windows.Forms.Button button4;
+ }
+}
+
diff --git a/ShortPATH/Form1.cs b/ShortPATH/Form1.cs
new file mode 100644
index 0000000..6d8e681
--- /dev/null
+++ b/ShortPATH/Form1.cs
@@ -0,0 +1,490 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+
+namespace ShortPATH
+{
+ public partial class Form1 : Form
+ {
+ private Boolean FirstRun = false;
+ private Boolean PATHUpdated = false;
+
+ private string AppTitle = "ShortPATH";
+ private string DefaultNewShortcutIdentifier = "new_shortcut";
+ private List CommandFileExtensions = new List() { "exe", "bat", "cmd", "msi" };
+
+ private string DirectoryPath;
+
+ private List shortcuts;
+
+ const int HWND_BROADCAST = 0xffff;
+ const uint WM_SETTINGCHANGE = 0x001a;
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ static extern bool SendNotifyMessage(IntPtr hWnd, uint Msg,
+ UIntPtr wParam, string lParam);
+
+ public Form1()
+ {
+ InitializeComponent();
+
+ DirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + AppTitle;
+
+ // See if we can access (or create & access) the application directory in AppData
+ if (!CheckAppData())
+ {
+ MessageBox.Show("Failed to load application data directory.", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ System.Environment.Exit(0);
+ }
+
+ // See if the application directory is in the PATH environment variable (or add & check)
+ if (!CheckPATH())
+ {
+ MessageBox.Show("Failed add shortcut directory to PATH environment variable.", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ System.Environment.Exit(0);
+ }
+
+ // See if we can load any Shortcuts
+ if (!LoadShortcuts() || !LoadShortcutList())
+ {
+ MessageBox.Show("Failed to load shortcuts.", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ System.Environment.Exit(0);
+ }
+
+ Console.WriteLine(AppTitle + " loaded");
+ }
+
+ // Check if we can access (or create & access) the application directory in AppData
+ public Boolean CheckAppData()
+ {
+ try
+ {
+ // If the application directory exists we're done here
+ if (Directory.Exists(DirectoryPath))
+ {
+ return true;
+ }
+
+ // Create the directory
+ DirectoryInfo di = Directory.CreateDirectory(DirectoryPath);
+
+ // No exception means the directory has been created
+ Console.WriteLine("Directory created: " + DirectoryPath);
+
+ // This mostly indicates a firstrun so we can show an informative message later
+ FirstRun = true;
+
+ return true;
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine("The process failed: {0}", exception.ToString());
+ }
+
+ return false;
+ }
+
+ // Check if the application directory is in the PATH environment variable (or add & check)
+ public Boolean CheckPATH(Boolean addToPATH = true)
+ {
+ // Store into CURRENT_USER for easy portability
+ string registeryKey = "HKEY_CURRENT_USER\\Environment";
+ string registeryValue = "Path";
+
+ try
+ {
+
+ // Get current paths from registery
+ string pathVariable = (string) Registry.GetValue(registeryKey, registeryValue, "");
+ string[] paths = pathVariable.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+
+ // A list to remember all current directory paths in the current PATH variable if we must edit it
+ List pathList = new List();
+
+ // See if our directory is present
+ foreach (string path in paths)
+ {
+ pathList.Add(path);
+
+ if (path == DirectoryPath) {
+ return true;
+ }
+ }
+
+ // addToPATH will be false if this is our second try to add the path
+ if(addToPATH == false) {
+ return false;
+ }
+
+ // Add our directory to the PATH variable list
+ pathList.Add(DirectoryPath);
+
+ // Set the new registry value
+ pathVariable = String.Join(";", pathList);
+ Registry.SetValue(registeryKey, registeryValue, pathVariable);
+ Console.WriteLine("PATH updated: " + pathVariable);
+
+ // Signal the environment so the new PATH is used (not accurate)
+ SendNotifyMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, (UIntPtr)0, "Environment");
+
+ // Show a nice message to explain things
+ MessageBox.Show(
+ "The PATH Environment variable of this user account has been updated. " +
+ "You will have to sign out and sign in again before changes are reflected. " +
+ "After that changes to the shortcuts will update instantly.",
+ AppTitle,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Information
+ );
+
+ // If the PATH was updated we can make the messagebox when a file is saved context-aware
+ PATHUpdated = true;
+
+ // Double check the PATH
+ return CheckPATH(false);
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine("The process failed: {0}", exception.ToString());
+ }
+
+ return false;
+ }
+
+ // Load all Shortcuts into a List
+ private Boolean LoadShortcuts()
+ {
+ shortcuts = new List();
+
+ DirectoryInfo dir = new DirectoryInfo(DirectoryPath);
+ FileInfo[] Files = dir.GetFiles("*.bat");
+
+ foreach (FileInfo file in Files)
+ {
+ string name = Path.GetFileNameWithoutExtension(file.Name);
+ shortcuts.Add(new Shortcut(DirectoryPath, name));
+ }
+
+ return true;
+ }
+
+ // Load the Shortcut List into the ListBox
+ public Boolean LoadShortcutList(string selectedItem = null)
+ {
+ try
+ {
+ // Update Data source
+ listBox1.DataSource = null;
+ listBox1.DataSource = shortcuts;
+ listBox1.DisplayMember = "Identifier";
+ listBox1.ValueMember = "Folder";
+
+ // Check if we need to select an item
+ if(selectedItem == null)
+ {
+ listBox1.SelectedIndex = -1;
+ } else
+ {
+ // Get index in ListBox by string
+ int index = listBox1.FindString(selectedItem);
+
+ // Select it if it's found
+ if (index != -1)
+ {
+ listBox1.SetSelected(index, true);
+ }
+ }
+
+ return true;
+ }
+ catch (Exception exception) {
+ Console.WriteLine("The process failed: {0}", exception.ToString());
+ }
+
+ return false;
+ }
+
+ // Load the right panel when the listbox updates
+ private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ // The index of the listbox matches the index in the list of Shortcuts
+ int index = listBox1.SelectedIndex;
+
+ // If nothing selected reset the right panel
+ if (index == -1)
+ {
+ textBox1.Text = "";
+ textBox1.Enabled = false;
+
+ textBox2.Text = "";
+ textBox2.Enabled = false;
+
+ button2.Enabled = false;
+ button3.Enabled = false;
+ button4.Enabled = false;
+
+ } else
+ {
+ // Load the shortcut into the right panel
+ try
+ {
+ Shortcut shortcut = shortcuts.ElementAt(index);
+
+ textBox1.Text = shortcut.Identifier;
+ textBox1.Enabled = true;
+
+ textBox2.Text = shortcut.Folder;
+ textBox2.Enabled = true;
+
+ button2.Enabled = true;
+ button3.Enabled = true;
+ button4.Enabled = true;
+
+ } catch (Exception exception){
+ Console.WriteLine("The process failed: {0}", exception.ToString());
+ }
+
+ }
+
+
+ }
+
+ // Save
+ private void button3_Click(object sender, EventArgs e)
+ {
+ // Check for filled in fields
+ if (textBox1.Text == "" || textBox2.Text == "")
+ {
+ MessageBox.Show("Both the shortcut identifier and folder should be filled in.",
+ AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
+ return;
+ }
+
+ // Check for a valid filename
+ if (!IsValidFilename(textBox1.Text))
+ {
+ MessageBox.Show("Invalid shortcut identifier. It should be able to be saved as a file",
+ AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
+ return;
+ }
+
+ // Check for a valid directory path
+ if (!IsValidDirectoryPath(textBox2.Text))
+ {
+ MessageBox.Show("Invalid folder path", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
+ return;
+ }
+
+ // The index of the listbox matches the index in the list of Shortcuts
+ int index = listBox1.SelectedIndex;
+
+ if (index != -1)
+ {
+ // Get the Shortcut from the list and update its properties, temporary Shortcuts are also stored in the list
+ Shortcut shortcut = shortcuts.ElementAt(index);
+
+ // Make sure the Shortcut does not exist yet by checking the ListBox
+ if(shortcut.Identifier != textBox1.Text)
+ {
+ if (listBox1.FindString(textBox1.Text) != -1)
+ {
+ MessageBox.Show("This shortcut identifier is already in use.", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
+ return;
+ }
+ }
+
+ // Check if the command is already in use (second parameter is the ignored Shortcut identifier)
+ if (CommandExistsInPATH(textBox1.Text, shortcut.Identifier))
+ {
+ MessageBox.Show("The command \"" + textBox1.Text + "\" is already in use by the environment.",
+ AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
+ return;
+ }
+
+ // Shortcut object properties
+ shortcut.Identifier = textBox1.Text;
+ shortcut.Folder = textBox2.Text;
+ shortcut.SaveFile();
+
+ // Reload everything
+ LoadShortcuts();
+ LoadShortcutList();
+
+ // On the first run we'll show a messagebox for more information
+ if (FirstRun)
+ {
+ // When the PATH is updated as well we'll show this context-aware messagebox
+ if (PATHUpdated)
+ {
+ MessageBox.Show(
+ "When you sign out and back in again, you will be able to run commands directly in the chosen folder by running: " +
+ "\"" + shortcut.Identifier + " \". ",
+ AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ } else
+ {
+ MessageBox.Show("You can now run commands directly in the chosen folder by running: " +
+ "\"" + shortcut.Identifier + " \". ",
+ AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ // Next saves shouldn't annoy the user
+ FirstRun = false;
+ PATHUpdated = false;
+ }
+ }
+ }
+
+ // Add
+ private void button1_Click(object sender, EventArgs e)
+ {
+ // Reload shortcuts to remove any non saved shortcuts
+ LoadShortcuts();
+
+ // Check for the default new shortcut string and get the next available one if it already exists
+ string shortcutIdentifier = DefaultNewShortcutIdentifier;
+ if (listBox1.FindString(shortcutIdentifier) != -1)
+ {
+ int nextNumber = 2;
+
+ // While we've not found the next identifier
+ while (shortcutIdentifier == DefaultNewShortcutIdentifier)
+ {
+ string nextShortcutIdentifier = DefaultNewShortcutIdentifier + nextNumber.ToString();
+
+ // If the next identifier is not yet in the list we'll leave the while loop by updating the identifier we'll use
+ if(listBox1.FindString(nextShortcutIdentifier) == -1)
+ {
+ shortcutIdentifier = nextShortcutIdentifier;
+ } else
+ {
+ nextNumber++;
+ }
+ }
+ }
+
+ // Add a shortcut to the list and show it in the right panel. It is not saved yet at this point
+ shortcuts.Add(new Shortcut(DirectoryPath, shortcutIdentifier));
+ LoadShortcutList(shortcutIdentifier);
+
+ // Select the shortcut text
+ textBox1.Select();
+ }
+
+ // Remove
+ private void button4_Click(object sender, EventArgs e)
+ {
+ // The index of the listbox matches the index in the list of Shortcuts
+ int index = listBox1.SelectedIndex;
+
+ if (index != -1)
+ {
+ // Select Shortcut and delete it
+ Shortcut shortcut = shortcuts.ElementAt(index);
+ shortcut.Delete();
+
+ // Reload everything
+ LoadShortcuts();
+ LoadShortcutList();
+ }
+ }
+
+ // Browse folder
+ private void button2_Click(object sender, EventArgs e)
+ {
+ using (var fbd = new FolderBrowserDialog())
+ {
+ DialogResult result = fbd.ShowDialog();
+
+ if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
+ {
+ textBox2.Text = fbd.SelectedPath;
+ }
+ }
+ }
+
+ // Simulate a Save button click when we press enter in the field
+ private void textBox1_KeyUp(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter)
+ {
+ button3_Click(this, new EventArgs());
+ }
+ }
+
+ // Simulate a Save button click when we press enter in the field
+ private void textBox2_KeyUp(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter)
+ {
+ button3_Click(this, new EventArgs());
+ }
+ }
+
+ // Check if a string is a valid filename
+ bool IsValidFilename(string testName)
+ {
+ // https://stackoverflow.com/a/62855/5865844
+ Regex containsABadCharacter = new Regex("["
+ + Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars())) + "]");
+ if (containsABadCharacter.IsMatch(testName)) { return false; };
+
+ return true;
+ }
+
+ // Check if a string is a valid directory path
+ private bool IsValidDirectoryPath(string path, bool exactPath = true)
+ {
+ // https://stackoverflow.com/a/48820213/5865844
+ bool isValid = true;
+
+ try {
+ string fullPath = Path.GetFullPath(path);
+
+ if (exactPath){
+ string root = Path.GetPathRoot(path);
+ isValid = string.IsNullOrEmpty(root.Trim(new char[] { '\\', '/' })) == false;
+ } else {
+ isValid = Path.IsPathRooted(path);
+ }
+ } catch (Exception ex) {
+ isValid = false;
+ }
+
+ return isValid;
+ }
+
+ // Check if the given string can already be used as a command
+ private bool CommandExistsInPATH(string possibleCommand, string ignoredIdentifier = null)
+ {
+ string PATH = System.Environment.GetEnvironmentVariable("PATH");
+ string[] paths = PATH.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+
+ // See if our directory is present
+ foreach (string path in paths)
+ {
+ string currentDirectoryPath = path.Trim(new[] { '\\', '/' });
+
+ if(currentDirectoryPath != DirectoryPath)
+ {
+ // https://stackoverflow.com/a/50856314/5865844
+ //foreach (var fileExtension in new[] { "exe", "bat", "cmd", "msi" })
+ foreach (var fileExtension in CommandFileExtensions)
+ {
+ string filePath = currentDirectoryPath + "\\" + possibleCommand + "." + fileExtension;
+ if (File.Exists(filePath))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/ShortPATH/Form1.resx b/ShortPATH/Form1.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/ShortPATH/Form1.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ShortPATH/Program.cs b/ShortPATH/Program.cs
new file mode 100644
index 0000000..5f467fa
--- /dev/null
+++ b/ShortPATH/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ShortPATH
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new Form1());
+ }
+ }
+}
diff --git a/ShortPATH/Properties/AssemblyInfo.cs b/ShortPATH/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e2e8a5b
--- /dev/null
+++ b/ShortPATH/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ShortPATH")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("yanikore")]
+[assembly: AssemblyProduct("ShortPATH")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a63270e0-85cd-4201-94a8-54802601cf7e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ShortPATH/Properties/Resources.Designer.cs b/ShortPATH/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..240b7e5
--- /dev/null
+++ b/ShortPATH/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ShortPATH.Properties
+{
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ShortPATH.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/ShortPATH/Properties/Resources.resx b/ShortPATH/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/ShortPATH/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ShortPATH/Properties/Settings.Designer.cs b/ShortPATH/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..de473a3
--- /dev/null
+++ b/ShortPATH/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ShortPATH.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/ShortPATH/Properties/Settings.settings b/ShortPATH/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/ShortPATH/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/ShortPATH/ShortPATH.csproj b/ShortPATH/ShortPATH.csproj
new file mode 100644
index 0000000..e36d8c6
--- /dev/null
+++ b/ShortPATH/ShortPATH.csproj
@@ -0,0 +1,83 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A63270E0-85CD-4201-94A8-54802601CF7E}
+ WinExe
+ ShortPATH
+ ShortPATH
+ v4.6.1
+ 512
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ Form1.cs
+
+
+
+
+ Form1.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ShortPATH/Shortcut.cs b/ShortPATH/Shortcut.cs
new file mode 100644
index 0000000..44f5fc3
--- /dev/null
+++ b/ShortPATH/Shortcut.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace ShortPATH
+{
+ class Shortcut
+ {
+ private string DirectoryPath;
+
+ private string FilePath;
+
+ public string Identifier { get; set; }
+
+ public string Folder { get; set; }
+
+ private string FileContents = "@echo off\r\n" +
+ "SET org_dir=%cd%\r\n" +
+ "cd /d \"{folder}\"\r\n" +
+ "%*\r\n" +
+ "cd /d \"%org_dir%\"";
+
+ public Shortcut(string directoryPath, string identifier = null)
+ {
+ DirectoryPath = directoryPath;
+
+ if(identifier != null)
+ {
+ Identifier = identifier;
+ FilePath = GetFilePath(identifier);
+ LoadFile();
+ }
+ }
+
+ private Boolean LoadFile()
+ {
+ if (File.Exists(FilePath))
+ {
+ string contents = null;
+
+ try
+ {
+ using (StreamReader streamReader = new StreamReader(FilePath, Encoding.UTF8))
+ {
+ contents = streamReader.ReadToEnd();
+ }
+
+ } catch(Exception exception)
+ {
+ Console.WriteLine("The process failed: {0}", exception.ToString());
+ }
+
+ if (!String.IsNullOrEmpty(contents))
+ {
+ Regex regex = new Regex("cd /d \"(.+?)\"");
+ Match match = regex.Match(contents);
+
+ if (match.Success)
+ {
+ string folder = match.Groups[1].ToString();
+
+ if (!String.IsNullOrEmpty(folder))
+ {
+ Folder = folder.Replace("\\\\", "\\");
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public void SaveFile()
+ {
+ string outputFile = GetFilePath(Identifier);
+
+ // If the identifier has changed we should remove the old file
+ if (outputFile != FilePath) {
+ File.Delete(FilePath);
+ }
+
+ string contents = FileContents.Replace("{folder}", Folder.Replace("\\", "\\\\"));
+
+ File.WriteAllText(outputFile, contents);
+
+ FilePath = outputFile;
+ }
+
+ public void Delete()
+ {
+ if (File.Exists(FilePath))
+ {
+ File.Delete(FilePath);
+ }
+ }
+
+ private string GetFilePath(string identifier)
+ {
+ return DirectoryPath + "\\" + identifier + ".bat";
+ }
+
+ public override string ToString() {
+ return Identifier;
+ }
+ }
+}