From 16bf3ed3397a94a957a5dccaaed7f170e6777e0a Mon Sep 17 00:00:00 2001 From: zmjack Date: Wed, 9 Dec 2020 21:19:58 +0800 Subject: [PATCH] v1.0.5 --- PortProxyGUI - NET/About.cs | 1 - PortProxyGUI - NET/PortProxyGUI - NET.csproj | 30 +++-- PortProxyGUI - NET/PortProxyGUI.Designer.cs | 58 ++++++---- PortProxyGUI - NET/PortProxyGUI.cs | 89 ++++++++++++--- PortProxyGUI - NET/PortProxyGUI.resx | 98 +++++++++------- PortProxyGUI - NET/PortProxyGUI.zh-CN.resx | 11 +- PortProxyGUI - NET/Properties/AssemblyInfo.cs | 4 +- ...y.Designer.cs => SetProxyForm.Designer.cs} | 30 ++--- .../{NewProxy.cs => SetProxyForm.cs} | 54 +++++++-- .../SetProxyForm.resx | 26 ++--- .../SetProxyForm.zh-CN.resx | 6 +- PortProxyGUI - NET/app.manifest | 20 ++-- PortProxyGUI.Shared/ListViewColumnSorter.cs | 105 ++++++++++++++++++ .../PortProxyGUI.Shared.projitems | 1 + PortProxyGUI/About.cs | 1 - PortProxyGUI/PortProxyGUI.Designer.cs | 58 ++++++---- PortProxyGUI/PortProxyGUI.cs | 89 ++++++++++++--- PortProxyGUI/PortProxyGUI.csproj | 26 ++--- PortProxyGUI/PortProxyGUI.resx | 98 +++++++++------- PortProxyGUI/PortProxyGUI.zh-CN.resx | 11 +- PortProxyGUI/Program.cs | 2 + ...y.Designer.cs => SetProxyForm.Designer.cs} | 30 ++--- PortProxyGUI/{NewProxy.cs => SetProxyForm.cs} | 54 +++++++-- .../SetProxyForm.resx | 26 ++--- .../SetProxyForm.zh-CN.resx | 6 +- docs/ui.png | Bin 11821 -> 12787 bytes 26 files changed, 639 insertions(+), 295 deletions(-) rename PortProxyGUI - NET/{NewProxy.Designer.cs => SetProxyForm.Designer.cs} (87%) rename PortProxyGUI - NET/{NewProxy.cs => SetProxyForm.cs} (52%) rename PortProxyGUI/NewProxy.resx => PortProxyGUI - NET/SetProxyForm.resx (99%) rename PortProxyGUI/NewProxy.zh-CN.resx => PortProxyGUI - NET/SetProxyForm.zh-CN.resx (99%) create mode 100644 PortProxyGUI.Shared/ListViewColumnSorter.cs rename PortProxyGUI/{NewProxy.Designer.cs => SetProxyForm.Designer.cs} (87%) rename PortProxyGUI/{NewProxy.cs => SetProxyForm.cs} (52%) rename PortProxyGUI - NET/NewProxy.resx => PortProxyGUI/SetProxyForm.resx (99%) rename PortProxyGUI - NET/NewProxy.zh-CN.resx => PortProxyGUI/SetProxyForm.zh-CN.resx (99%) diff --git a/PortProxyGUI - NET/About.cs b/PortProxyGUI - NET/About.cs index de4243c..8106a60 100644 --- a/PortProxyGUI - NET/About.cs +++ b/PortProxyGUI - NET/About.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Reflection; using System.Windows.Forms; namespace PortProxyGUI diff --git a/PortProxyGUI - NET/PortProxyGUI - NET.csproj b/PortProxyGUI - NET/PortProxyGUI - NET.csproj index c371f90..fb2f641 100644 --- a/PortProxyGUI - NET/PortProxyGUI - NET.csproj +++ b/PortProxyGUI - NET/PortProxyGUI - NET.csproj @@ -25,6 +25,7 @@ 0 1.0.0.%2a false + true true @@ -52,6 +53,21 @@ icon.ico + + BEF27898E4C102E806F3241497048E740EC39033 + + + PortProxyGUI - NET_TemporaryKey.pfx + + + false + + + true + + + LocalIntranet + @@ -70,11 +86,11 @@ About.cs - + Form - - NewProxy.cs + + SetProxyForm.cs Form @@ -90,11 +106,11 @@ About.cs - - NewProxy.cs + + SetProxyForm.cs - - NewProxy.cs + + SetProxyForm.cs PortProxyGUI.cs diff --git a/PortProxyGUI - NET/PortProxyGUI.Designer.cs b/PortProxyGUI - NET/PortProxyGUI.Designer.cs index 182071b..ad33b70 100644 --- a/PortProxyGUI - NET/PortProxyGUI.Designer.cs +++ b/PortProxyGUI - NET/PortProxyGUI.Designer.cs @@ -37,12 +37,13 @@ this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_New = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_Modify = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_Delete = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_Refresh = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_About = new System.Windows.Forms.ToolStripMenuItem(); this.contextMenuStrip1.SuspendLayout(); this.SuspendLayout(); // @@ -61,6 +62,8 @@ this.listView1.Name = "listView1"; this.listView1.UseCompatibleStateImageBehavior = false; this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick); + this.listView1.DoubleClick += new System.EventHandler(this.listView1_DoubleClick); this.listView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseUp); // // columnHeader1 @@ -86,45 +89,51 @@ // contextMenuStrip1 // this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem1, - this.toolStripMenuItem2, + this.toolStripMenuItem_New, + this.toolStripMenuItem_Modify, + this.toolStripMenuItem_Delete, this.toolStripSeparator1, - this.toolStripMenuItem3, + this.toolStripMenuItem_Refresh, this.toolStripSeparator2, - this.toolStripMenuItem4}); + this.toolStripMenuItem_About}); this.contextMenuStrip1.Name = "contextMenuStrip1"; resources.ApplyResources(this.contextMenuStrip1, "contextMenuStrip1"); this.contextMenuStrip1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.contextMenuStrip1_MouseClick); // - // toolStripMenuItem1 + // toolStripMenuItem_New // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1"); + this.toolStripMenuItem_New.Name = "toolStripMenuItem_New"; + resources.ApplyResources(this.toolStripMenuItem_New, "toolStripMenuItem_New"); // - // toolStripMenuItem2 + // toolStripMenuItem_Modify // - this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - resources.ApplyResources(this.toolStripMenuItem2, "toolStripMenuItem2"); + this.toolStripMenuItem_Modify.Name = "toolStripMenuItem_Modify"; + resources.ApplyResources(this.toolStripMenuItem_Modify, "toolStripMenuItem_Modify"); + // + // toolStripMenuItem_Delete + // + this.toolStripMenuItem_Delete.Name = "toolStripMenuItem_Delete"; + resources.ApplyResources(this.toolStripMenuItem_Delete, "toolStripMenuItem_Delete"); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; resources.ApplyResources(this.toolStripSeparator1, "toolStripSeparator1"); // - // toolStripMenuItem3 + // toolStripMenuItem_Refresh // - this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - resources.ApplyResources(this.toolStripMenuItem3, "toolStripMenuItem3"); + this.toolStripMenuItem_Refresh.Name = "toolStripMenuItem_Refresh"; + resources.ApplyResources(this.toolStripMenuItem_Refresh, "toolStripMenuItem_Refresh"); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; resources.ApplyResources(this.toolStripSeparator2, "toolStripSeparator2"); // - // toolStripMenuItem4 + // toolStripMenuItem_About // - this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - resources.ApplyResources(this.toolStripMenuItem4, "toolStripMenuItem4"); + this.toolStripMenuItem_About.Name = "toolStripMenuItem_About"; + resources.ApplyResources(this.toolStripMenuItem_About, "toolStripMenuItem_About"); // // PortProxyGUI // @@ -144,15 +153,16 @@ private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ColumnHeader columnHeader2; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_New; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_Delete; private System.Windows.Forms.ColumnHeader columnHeader3; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem3; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_Refresh; private System.Windows.Forms.ColumnHeader columnHeader4; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem4; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_About; private System.Windows.Forms.ColumnHeader columnHeader5; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_Modify; } } diff --git a/PortProxyGUI - NET/PortProxyGUI.cs b/PortProxyGUI - NET/PortProxyGUI.cs index 308b6a5..90218f2 100644 --- a/PortProxyGUI - NET/PortProxyGUI.cs +++ b/PortProxyGUI - NET/PortProxyGUI.cs @@ -10,12 +10,15 @@ namespace PortProxyGUI { public partial class PortProxyGUI : Form { - public NewProxy NewProxyForm; + public SetProxyForm SetProxyForm; public About AboutForm; + private ListViewColumnSorter lvwColumnSorter; public PortProxyGUI() { InitializeComponent(); + lvwColumnSorter = new ListViewColumnSorter(); + listView1.ListViewItemSorter = lvwColumnSorter; } private void PortProxyGUI_Load(object sender, EventArgs e) @@ -34,10 +37,23 @@ namespace PortProxyGUI var listenPort = subItems[2].Text; var output = CmdRunner.Execute($"netsh interface portproxy delete {type} listenaddress={listenOn} listenport={listenPort}"); } - RefreshProxyList(); } + private void SetProxyForUpdate(SetProxyForm form) + { + var item = listView1.SelectedItems.OfType().FirstOrDefault(); + { + var subItems = item.SubItems.OfType().ToArray(); + var type = subItems[0].Text; + var listenOn = subItems[1].Text; + var listenPort = subItems[2].Text; + var connectTo = subItems[3].Text; + var connectPort = subItems[4].Text; + form.UseUpdateMode(type, listenOn, listenPort, connectTo, connectPort); + } + } + public void RefreshProxyList() { var output = CmdRunner.Execute("netsh interface portproxy show all"); @@ -88,19 +104,22 @@ namespace PortProxyGUI switch (selected.Text) { - case string s when s == toolStripMenuItem1.Text: - if (NewProxyForm == null) - { - NewProxyForm = new NewProxy(this); - NewProxyForm.Show(); - } - else NewProxyForm.Show(); + case string s when s == toolStripMenuItem_New.Text: + if (SetProxyForm == null) SetProxyForm = new SetProxyForm(this); + SetProxyForm.UseNormalMode(); + SetProxyForm.Show(); break; - case string s when s == toolStripMenuItem3.Text: RefreshProxyList(); break; - case string s when s == toolStripMenuItem2.Text: DeleteSelectedProxies(); break; + case string s when s == toolStripMenuItem_Modify.Text: + if (SetProxyForm == null) SetProxyForm = new SetProxyForm(this); + SetProxyForUpdate(SetProxyForm); + SetProxyForm.Show(); + break; - case string s when s == toolStripMenuItem4.Text: + case string s when s == toolStripMenuItem_Refresh.Text: RefreshProxyList(); break; + case string s when s == toolStripMenuItem_Delete.Text: DeleteSelectedProxies(); break; + + case string s when s == toolStripMenuItem_About.Text: if (AboutForm == null) { AboutForm = new About(this); @@ -116,10 +135,50 @@ namespace PortProxyGUI { if (sender is ListView _sender) { - if (e.Button == MouseButtons.Right && _sender.SelectedItems.OfType().Any()) - toolStripMenuItem2.Enabled = true; - else toolStripMenuItem2.Enabled = false; + var selectAny = e.Button == MouseButtons.Right && _sender.SelectedItems.OfType().Any(); + toolStripMenuItem_Delete.Enabled = selectAny; + toolStripMenuItem_Modify.Enabled = selectAny; } } + + private void listView1_DoubleClick(object sender, EventArgs e) + { + if (sender is ListView _sender) + { + var selectAny = _sender.SelectedItems.OfType().Any(); + if (selectAny) + { + if (SetProxyForm == null) SetProxyForm = new SetProxyForm(this); + SetProxyForUpdate(SetProxyForm); + SetProxyForm.Show(); + } + } + } + + private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) + { + // Determine if clicked column is already the column that is being sorted. + if (e.Column == lvwColumnSorter.SortColumn) + { + // Reverse the current sort direction for this column. + if (lvwColumnSorter.Order == SortOrder.Ascending) + { + lvwColumnSorter.Order = SortOrder.Descending; + } + else + { + lvwColumnSorter.Order = SortOrder.Ascending; + } + } + else + { + // Set the column number that is to be sorted; default to ascending. + lvwColumnSorter.SortColumn = e.Column; + lvwColumnSorter.Order = SortOrder.Ascending; + } + + // Perform the sort with these new sort options. + listView1.Sort(); + } } } diff --git a/PortProxyGUI - NET/PortProxyGUI.resx b/PortProxyGUI - NET/PortProxyGUI.resx index 9ca12d2..d4d4a1a 100644 --- a/PortProxyGUI - NET/PortProxyGUI.resx +++ b/PortProxyGUI - NET/PortProxyGUI.resx @@ -149,8 +149,44 @@ 17, 17 + + 180, 22 + + + New + + + 180, 22 + + + Modify + + + 180, 22 + + + Delete + + + 177, 6 + + + 180, 22 + + + Refresh + + + 177, 6 + + + 180, 22 + + + About + - 121, 104 + 181, 148 contextMenuStrip1 @@ -186,36 +222,6 @@ 1 - - 120, 22 - - - New - - - 120, 22 - - - Delete - - - 117, 6 - - - 120, 22 - - - Refresh - - - 117, 6 - - - 120, 22 - - - About - True @@ -2422,16 +2428,22 @@ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem1 + + toolStripMenuItem_New - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem2 + + toolStripMenuItem_Modify - + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripMenuItem_Delete + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -2440,10 +2452,10 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem3 + + toolStripMenuItem_Refresh - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -2452,10 +2464,10 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem4 + + toolStripMenuItem_About - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/PortProxyGUI - NET/PortProxyGUI.zh-CN.resx b/PortProxyGUI - NET/PortProxyGUI.zh-CN.resx index 6653a22..575a979 100644 --- a/PortProxyGUI - NET/PortProxyGUI.zh-CN.resx +++ b/PortProxyGUI - NET/PortProxyGUI.zh-CN.resx @@ -164,7 +164,7 @@ 0, 0 - + 删除 @@ -179,7 +179,7 @@ 3, 2, 3, 2 - + 新建 @@ -191,7 +191,7 @@ columnHeader1 - + 刷新 @@ -243,7 +243,7 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 关于 @@ -309,4 +309,7 @@ zh-Hans + + 修改 + \ No newline at end of file diff --git a/PortProxyGUI - NET/Properties/AssemblyInfo.cs b/PortProxyGUI - NET/Properties/AssemblyInfo.cs index 23a6dc3..2d3f136 100644 --- a/PortProxyGUI - NET/Properties/AssemblyInfo.cs +++ b/PortProxyGUI - NET/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // 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.3.0")] -[assembly: AssemblyFileVersion("1.0.3.0")] +[assembly: AssemblyVersion("1.0.5.0")] +[assembly: AssemblyFileVersion("1.0.5.0")] diff --git a/PortProxyGUI - NET/NewProxy.Designer.cs b/PortProxyGUI - NET/SetProxyForm.Designer.cs similarity index 87% rename from PortProxyGUI - NET/NewProxy.Designer.cs rename to PortProxyGUI - NET/SetProxyForm.Designer.cs index b5ea27d..8fbfe1b 100644 --- a/PortProxyGUI - NET/NewProxy.Designer.cs +++ b/PortProxyGUI - NET/SetProxyForm.Designer.cs @@ -1,6 +1,6 @@ namespace PortProxyGUI { - partial class NewProxy + partial class SetProxyForm { /// /// Required designer variable. @@ -28,14 +28,14 @@ /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NewProxy)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SetProxyForm)); this.label1 = new System.Windows.Forms.Label(); this.textBox_listenOn = new System.Windows.Forms.TextBox(); this.label2 = new System.Windows.Forms.Label(); this.textBox_connectTo = new System.Windows.Forms.TextBox(); this.textBox_connectPort = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); + this.button_submit = new System.Windows.Forms.Button(); this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.textBox_listenPort = new System.Windows.Forms.TextBox(); @@ -72,12 +72,12 @@ resources.ApplyResources(this.label3, "label3"); this.label3.Name = "label3"; // - // button1 + // button_submit // - resources.ApplyResources(this.button1, "button1"); - this.button1.Name = "button1"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + resources.ApplyResources(this.button_submit, "button_submit"); + this.button_submit.Name = "button_submit"; + this.button_submit.UseVisualStyleBackColor = true; + this.button_submit.Click += new System.EventHandler(this.button_submit_Click); // // label4 // @@ -106,16 +106,16 @@ resources.GetString("comboBox_type.Items4")}); this.comboBox_type.Name = "comboBox_type"; // - // NewProxy + // SetProxyForm // - this.AcceptButton = this.button1; + this.AcceptButton = this.button_submit; resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.comboBox_type); this.Controls.Add(this.textBox_listenPort); this.Controls.Add(this.label5); this.Controls.Add(this.label4); - this.Controls.Add(this.button1); + this.Controls.Add(this.button_submit); this.Controls.Add(this.label3); this.Controls.Add(this.textBox_connectPort); this.Controls.Add(this.textBox_connectTo); @@ -125,10 +125,10 @@ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.MaximizeBox = false; this.MinimizeBox = false; - this.Name = "NewProxy"; + this.Name = "SetProxyForm"; this.TopMost = true; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.NewProxy_FormClosing); - this.Load += new System.EventHandler(this.NewProxy_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SetProxyForm_FormClosing); + this.Load += new System.EventHandler(this.SetProxyForm_Load); this.ResumeLayout(false); this.PerformLayout(); @@ -142,7 +142,7 @@ private System.Windows.Forms.TextBox textBox_connectTo; private System.Windows.Forms.TextBox textBox_connectPort; private System.Windows.Forms.Label label3; - private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button_submit; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label5; private System.Windows.Forms.TextBox textBox_listenPort; diff --git a/PortProxyGUI - NET/NewProxy.cs b/PortProxyGUI - NET/SetProxyForm.cs similarity index 52% rename from PortProxyGUI - NET/NewProxy.cs rename to PortProxyGUI - NET/SetProxyForm.cs index a8814c0..39f5c2c 100644 --- a/PortProxyGUI - NET/NewProxy.cs +++ b/PortProxyGUI - NET/SetProxyForm.cs @@ -6,21 +6,48 @@ using System.Windows.Forms; namespace PortProxyGUI { - public partial class NewProxy : Form + public partial class SetProxyForm : Form { public readonly PortProxyGUI PortProxyGUI; - private string AutoString { get; } + public bool UpdateMode { get; private set; } + private string AutoTypeString { get; } - public NewProxy(PortProxyGUI portProxyGUI) + public SetProxyForm(PortProxyGUI portProxyGUI) { PortProxyGUI = portProxyGUI; InitializeComponent(); - AutoString = comboBox_type.Text = comboBox_type.Items.OfType().First(); + AutoTypeString = comboBox_type.Text = comboBox_type.Items.OfType().First(); } - private void AddPortProxy(string type, string listenOn, string listenPort, string connectTo, string connectPort) + public void UseNormalMode() { - var output = CmdRunner.Execute($"netsh interface portproxy add {type} listenaddress={listenOn} listenport={listenPort} connectaddress={connectTo} connectport={connectPort}"); + comboBox_type.Enabled = true; + textBox_listenOn.Enabled = true; + textBox_listenPort.Enabled = true; + comboBox_type.Text = AutoTypeString; + textBox_listenOn.Text = "*"; + textBox_listenPort.Text = ""; + textBox_connectTo.Text = ""; + textBox_connectPort.Text = ""; + UpdateMode = false; + } + + public void UseUpdateMode(string type, string listenOn, string listenPort, string connectTo, string connectPort) + { + comboBox_type.Enabled = false; + textBox_listenOn.Enabled = false; + textBox_listenPort.Enabled = false; + comboBox_type.Text = type; + textBox_listenOn.Text = listenOn; + textBox_listenPort.Text = listenPort; + textBox_connectTo.Text = connectTo; + textBox_connectPort.Text = connectPort; + UpdateMode = true; + } + + private void SetPortProxy(string type, string action, string listenOn, string listenPort, string connectTo, string connectPort) + { + var output = CmdRunner.Execute($"netsh interface portproxy {action} {type} listenaddress={listenOn} listenport={listenPort} connectaddress={connectTo} connectport={connectPort}"); Invoke((Action)(() => PortProxyGUI.RefreshProxyList())); } @@ -40,7 +67,7 @@ namespace PortProxyGUI return $"{from}to{to}"; } - private void button1_Click(object sender, EventArgs e) + private void button_submit_Click(object sender, EventArgs e) { var type = comboBox_type.Text.Trim(); var listenOn = textBox_listenOn.Text.Trim().ToLower(); @@ -60,7 +87,7 @@ namespace PortProxyGUI return; } - if (type == AutoString) type = GetPassType(listenOn, connectTo); + if (type == AutoTypeString) type = GetPassType(listenOn, connectTo); if (!new[] { "v4tov4", "v4tov6", "v6tov4", "v6tov6" }.Contains(type)) { @@ -68,16 +95,19 @@ namespace PortProxyGUI return; } - AddPortProxy(type, listenOn, listenPort, connectTo, connectPort); + SetPortProxy(type, UpdateMode ? "set" : "add", listenOn, listenPort, connectTo, connectPort); + Close(); } - private void NewProxy_Load(object sender, EventArgs e) + private void SetProxyForm_Load(object sender, EventArgs e) { + Top = PortProxyGUI.Top + (PortProxyGUI.Height - Height) / 2; + Left = PortProxyGUI.Left + (PortProxyGUI.Width - Width) / 2; } - private void NewProxy_FormClosing(object sender, FormClosingEventArgs e) + private void SetProxyForm_FormClosing(object sender, FormClosingEventArgs e) { - PortProxyGUI.NewProxyForm = null; + PortProxyGUI.SetProxyForm = null; } } diff --git a/PortProxyGUI/NewProxy.resx b/PortProxyGUI - NET/SetProxyForm.resx similarity index 99% rename from PortProxyGUI/NewProxy.resx rename to PortProxyGUI - NET/SetProxyForm.resx index 2b93f0b..c6e8f82 100644 --- a/PortProxyGUI/NewProxy.resx +++ b/PortProxyGUI - NET/SetProxyForm.resx @@ -285,28 +285,28 @@ 5 - + 227, 62 - + 74, 22 - + 6 - - Add + + Set - - button1 + + button_submit - + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + $this - + 4 @@ -2603,13 +2603,13 @@ 3, 2, 3, 2 - CenterScreen + Manual - New Proxy + Set Proxy - NewProxy + SetProxyForm System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/PortProxyGUI/NewProxy.zh-CN.resx b/PortProxyGUI - NET/SetProxyForm.zh-CN.resx similarity index 99% rename from PortProxyGUI/NewProxy.zh-CN.resx rename to PortProxyGUI - NET/SetProxyForm.zh-CN.resx index 27fe0b0..2dbaeb4 100644 --- a/PortProxyGUI/NewProxy.zh-CN.resx +++ b/PortProxyGUI - NET/SetProxyForm.zh-CN.resx @@ -201,8 +201,8 @@ 5 - - 添加 + + 设置 button1 @@ -283,7 +283,7 @@ 0 - 新建映射 + 设置映射 NewProxy diff --git a/PortProxyGUI - NET/app.manifest b/PortProxyGUI - NET/app.manifest index 169e618..06dba89 100644 --- a/PortProxyGUI - NET/app.manifest +++ b/PortProxyGUI - NET/app.manifest @@ -1,6 +1,6 @@  - + @@ -16,35 +16,31 @@ Remove this element if your application requires this virtualization for backwards compatibility. --> - + + + + + - - - - - - - - - - - + \ No newline at end of file diff --git a/PortProxyGUI.Shared/ListViewColumnSorter.cs b/PortProxyGUI.Shared/ListViewColumnSorter.cs new file mode 100644 index 0000000..2738154 --- /dev/null +++ b/PortProxyGUI.Shared/ListViewColumnSorter.cs @@ -0,0 +1,105 @@ +using System.Collections; +using System.Windows.Forms; + +namespace PortProxyGUI +{ + public class ListViewColumnSorter : IComparer + { + /// + /// Specifies the column to be sorted + /// + private int ColumnToSort; + + /// + /// Specifies the order in which to sort (i.e. 'Ascending'). + /// + private SortOrder OrderOfSort; + + /// + /// Case insensitive comparer object + /// + private CaseInsensitiveComparer ObjectCompare; + + /// + /// Class constructor. Initializes various elements + /// + public ListViewColumnSorter() + { + // Initialize the column to '0' + ColumnToSort = 0; + + // Initialize the sort order to 'none' + OrderOfSort = SortOrder.None; + + // Initialize the CaseInsensitiveComparer object + ObjectCompare = new CaseInsensitiveComparer(); + } + + /// + /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. + /// + /// First object to be compared + /// Second object to be compared + /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y' + public int Compare(object x, object y) + { + int compareResult; + ListViewItem listviewX, listviewY; + + // Cast the objects to be compared to ListViewItem objects + listviewX = (ListViewItem)x; + listviewY = (ListViewItem)y; + + // Compare the two items + compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text); + + // Calculate correct return value based on object comparison + if (OrderOfSort == SortOrder.Ascending) + { + // Ascending sort is selected, return normal result of compare operation + return compareResult; + } + else if (OrderOfSort == SortOrder.Descending) + { + // Descending sort is selected, return negative result of compare operation + return (-compareResult); + } + else + { + // Return '0' to indicate they are equal + return 0; + } + } + + /// + /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). + /// + public int SortColumn + { + set + { + ColumnToSort = value; + } + get + { + return ColumnToSort; + } + } + + /// + /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). + /// + public SortOrder Order + { + set + { + OrderOfSort = value; + } + get + { + return OrderOfSort; + } + } + + } +} diff --git a/PortProxyGUI.Shared/PortProxyGUI.Shared.projitems b/PortProxyGUI.Shared/PortProxyGUI.Shared.projitems index 7f9be85..c6f32f7 100644 --- a/PortProxyGUI.Shared/PortProxyGUI.Shared.projitems +++ b/PortProxyGUI.Shared/PortProxyGUI.Shared.projitems @@ -10,6 +10,7 @@ + diff --git a/PortProxyGUI/About.cs b/PortProxyGUI/About.cs index de4243c..8106a60 100644 --- a/PortProxyGUI/About.cs +++ b/PortProxyGUI/About.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Reflection; using System.Windows.Forms; namespace PortProxyGUI diff --git a/PortProxyGUI/PortProxyGUI.Designer.cs b/PortProxyGUI/PortProxyGUI.Designer.cs index 182071b..ad33b70 100644 --- a/PortProxyGUI/PortProxyGUI.Designer.cs +++ b/PortProxyGUI/PortProxyGUI.Designer.cs @@ -37,12 +37,13 @@ this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_New = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_Modify = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_Delete = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_Refresh = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem_About = new System.Windows.Forms.ToolStripMenuItem(); this.contextMenuStrip1.SuspendLayout(); this.SuspendLayout(); // @@ -61,6 +62,8 @@ this.listView1.Name = "listView1"; this.listView1.UseCompatibleStateImageBehavior = false; this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick); + this.listView1.DoubleClick += new System.EventHandler(this.listView1_DoubleClick); this.listView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseUp); // // columnHeader1 @@ -86,45 +89,51 @@ // contextMenuStrip1 // this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem1, - this.toolStripMenuItem2, + this.toolStripMenuItem_New, + this.toolStripMenuItem_Modify, + this.toolStripMenuItem_Delete, this.toolStripSeparator1, - this.toolStripMenuItem3, + this.toolStripMenuItem_Refresh, this.toolStripSeparator2, - this.toolStripMenuItem4}); + this.toolStripMenuItem_About}); this.contextMenuStrip1.Name = "contextMenuStrip1"; resources.ApplyResources(this.contextMenuStrip1, "contextMenuStrip1"); this.contextMenuStrip1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.contextMenuStrip1_MouseClick); // - // toolStripMenuItem1 + // toolStripMenuItem_New // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1"); + this.toolStripMenuItem_New.Name = "toolStripMenuItem_New"; + resources.ApplyResources(this.toolStripMenuItem_New, "toolStripMenuItem_New"); // - // toolStripMenuItem2 + // toolStripMenuItem_Modify // - this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - resources.ApplyResources(this.toolStripMenuItem2, "toolStripMenuItem2"); + this.toolStripMenuItem_Modify.Name = "toolStripMenuItem_Modify"; + resources.ApplyResources(this.toolStripMenuItem_Modify, "toolStripMenuItem_Modify"); + // + // toolStripMenuItem_Delete + // + this.toolStripMenuItem_Delete.Name = "toolStripMenuItem_Delete"; + resources.ApplyResources(this.toolStripMenuItem_Delete, "toolStripMenuItem_Delete"); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; resources.ApplyResources(this.toolStripSeparator1, "toolStripSeparator1"); // - // toolStripMenuItem3 + // toolStripMenuItem_Refresh // - this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - resources.ApplyResources(this.toolStripMenuItem3, "toolStripMenuItem3"); + this.toolStripMenuItem_Refresh.Name = "toolStripMenuItem_Refresh"; + resources.ApplyResources(this.toolStripMenuItem_Refresh, "toolStripMenuItem_Refresh"); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; resources.ApplyResources(this.toolStripSeparator2, "toolStripSeparator2"); // - // toolStripMenuItem4 + // toolStripMenuItem_About // - this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - resources.ApplyResources(this.toolStripMenuItem4, "toolStripMenuItem4"); + this.toolStripMenuItem_About.Name = "toolStripMenuItem_About"; + resources.ApplyResources(this.toolStripMenuItem_About, "toolStripMenuItem_About"); // // PortProxyGUI // @@ -144,15 +153,16 @@ private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ColumnHeader columnHeader2; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_New; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_Delete; private System.Windows.Forms.ColumnHeader columnHeader3; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem3; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_Refresh; private System.Windows.Forms.ColumnHeader columnHeader4; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem4; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_About; private System.Windows.Forms.ColumnHeader columnHeader5; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem_Modify; } } diff --git a/PortProxyGUI/PortProxyGUI.cs b/PortProxyGUI/PortProxyGUI.cs index 308b6a5..90218f2 100644 --- a/PortProxyGUI/PortProxyGUI.cs +++ b/PortProxyGUI/PortProxyGUI.cs @@ -10,12 +10,15 @@ namespace PortProxyGUI { public partial class PortProxyGUI : Form { - public NewProxy NewProxyForm; + public SetProxyForm SetProxyForm; public About AboutForm; + private ListViewColumnSorter lvwColumnSorter; public PortProxyGUI() { InitializeComponent(); + lvwColumnSorter = new ListViewColumnSorter(); + listView1.ListViewItemSorter = lvwColumnSorter; } private void PortProxyGUI_Load(object sender, EventArgs e) @@ -34,10 +37,23 @@ namespace PortProxyGUI var listenPort = subItems[2].Text; var output = CmdRunner.Execute($"netsh interface portproxy delete {type} listenaddress={listenOn} listenport={listenPort}"); } - RefreshProxyList(); } + private void SetProxyForUpdate(SetProxyForm form) + { + var item = listView1.SelectedItems.OfType().FirstOrDefault(); + { + var subItems = item.SubItems.OfType().ToArray(); + var type = subItems[0].Text; + var listenOn = subItems[1].Text; + var listenPort = subItems[2].Text; + var connectTo = subItems[3].Text; + var connectPort = subItems[4].Text; + form.UseUpdateMode(type, listenOn, listenPort, connectTo, connectPort); + } + } + public void RefreshProxyList() { var output = CmdRunner.Execute("netsh interface portproxy show all"); @@ -88,19 +104,22 @@ namespace PortProxyGUI switch (selected.Text) { - case string s when s == toolStripMenuItem1.Text: - if (NewProxyForm == null) - { - NewProxyForm = new NewProxy(this); - NewProxyForm.Show(); - } - else NewProxyForm.Show(); + case string s when s == toolStripMenuItem_New.Text: + if (SetProxyForm == null) SetProxyForm = new SetProxyForm(this); + SetProxyForm.UseNormalMode(); + SetProxyForm.Show(); break; - case string s when s == toolStripMenuItem3.Text: RefreshProxyList(); break; - case string s when s == toolStripMenuItem2.Text: DeleteSelectedProxies(); break; + case string s when s == toolStripMenuItem_Modify.Text: + if (SetProxyForm == null) SetProxyForm = new SetProxyForm(this); + SetProxyForUpdate(SetProxyForm); + SetProxyForm.Show(); + break; - case string s when s == toolStripMenuItem4.Text: + case string s when s == toolStripMenuItem_Refresh.Text: RefreshProxyList(); break; + case string s when s == toolStripMenuItem_Delete.Text: DeleteSelectedProxies(); break; + + case string s when s == toolStripMenuItem_About.Text: if (AboutForm == null) { AboutForm = new About(this); @@ -116,10 +135,50 @@ namespace PortProxyGUI { if (sender is ListView _sender) { - if (e.Button == MouseButtons.Right && _sender.SelectedItems.OfType().Any()) - toolStripMenuItem2.Enabled = true; - else toolStripMenuItem2.Enabled = false; + var selectAny = e.Button == MouseButtons.Right && _sender.SelectedItems.OfType().Any(); + toolStripMenuItem_Delete.Enabled = selectAny; + toolStripMenuItem_Modify.Enabled = selectAny; } } + + private void listView1_DoubleClick(object sender, EventArgs e) + { + if (sender is ListView _sender) + { + var selectAny = _sender.SelectedItems.OfType().Any(); + if (selectAny) + { + if (SetProxyForm == null) SetProxyForm = new SetProxyForm(this); + SetProxyForUpdate(SetProxyForm); + SetProxyForm.Show(); + } + } + } + + private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) + { + // Determine if clicked column is already the column that is being sorted. + if (e.Column == lvwColumnSorter.SortColumn) + { + // Reverse the current sort direction for this column. + if (lvwColumnSorter.Order == SortOrder.Ascending) + { + lvwColumnSorter.Order = SortOrder.Descending; + } + else + { + lvwColumnSorter.Order = SortOrder.Ascending; + } + } + else + { + // Set the column number that is to be sorted; default to ascending. + lvwColumnSorter.SortColumn = e.Column; + lvwColumnSorter.Order = SortOrder.Ascending; + } + + // Perform the sort with these new sort options. + listView1.Sort(); + } } } diff --git a/PortProxyGUI/PortProxyGUI.csproj b/PortProxyGUI/PortProxyGUI.csproj index 81e14d2..bb71042 100644 --- a/PortProxyGUI/PortProxyGUI.csproj +++ b/PortProxyGUI/PortProxyGUI.csproj @@ -14,7 +14,7 @@ portproxy TCP/IP redirector LICENSE.md Copyright © nstandard.net 2020 - 1.0.3 + 1.0.5 icon.ico @@ -42,18 +42,18 @@ About.cs - - Form - - - NewProxy.cs - Form PortProxyGUI.cs + + Form + + + SetProxyForm.cs + @@ -63,18 +63,18 @@ About.cs - - NewProxy.cs - - - NewProxy.cs - PortProxyGUI.cs PortProxyGUI.cs + + SetProxyForm.cs + + + SetProxyForm.cs + diff --git a/PortProxyGUI/PortProxyGUI.resx b/PortProxyGUI/PortProxyGUI.resx index 9ca12d2..d4d4a1a 100644 --- a/PortProxyGUI/PortProxyGUI.resx +++ b/PortProxyGUI/PortProxyGUI.resx @@ -149,8 +149,44 @@ 17, 17 + + 180, 22 + + + New + + + 180, 22 + + + Modify + + + 180, 22 + + + Delete + + + 177, 6 + + + 180, 22 + + + Refresh + + + 177, 6 + + + 180, 22 + + + About + - 121, 104 + 181, 148 contextMenuStrip1 @@ -186,36 +222,6 @@ 1 - - 120, 22 - - - New - - - 120, 22 - - - Delete - - - 117, 6 - - - 120, 22 - - - Refresh - - - 117, 6 - - - 120, 22 - - - About - True @@ -2422,16 +2428,22 @@ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem1 + + toolStripMenuItem_New - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem2 + + toolStripMenuItem_Modify - + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripMenuItem_Delete + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -2440,10 +2452,10 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem3 + + toolStripMenuItem_Refresh - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -2452,10 +2464,10 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - toolStripMenuItem4 + + toolStripMenuItem_About - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/PortProxyGUI/PortProxyGUI.zh-CN.resx b/PortProxyGUI/PortProxyGUI.zh-CN.resx index 6653a22..575a979 100644 --- a/PortProxyGUI/PortProxyGUI.zh-CN.resx +++ b/PortProxyGUI/PortProxyGUI.zh-CN.resx @@ -164,7 +164,7 @@ 0, 0 - + 删除 @@ -179,7 +179,7 @@ 3, 2, 3, 2 - + 新建 @@ -191,7 +191,7 @@ columnHeader1 - + 刷新 @@ -243,7 +243,7 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 关于 @@ -309,4 +309,7 @@ zh-Hans + + 修改 + \ No newline at end of file diff --git a/PortProxyGUI/Program.cs b/PortProxyGUI/Program.cs index f4a74cb..240cd83 100644 --- a/PortProxyGUI/Program.cs +++ b/PortProxyGUI/Program.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.Threading; using System.Windows.Forms; namespace PortProxyGUI diff --git a/PortProxyGUI/NewProxy.Designer.cs b/PortProxyGUI/SetProxyForm.Designer.cs similarity index 87% rename from PortProxyGUI/NewProxy.Designer.cs rename to PortProxyGUI/SetProxyForm.Designer.cs index b5ea27d..8fbfe1b 100644 --- a/PortProxyGUI/NewProxy.Designer.cs +++ b/PortProxyGUI/SetProxyForm.Designer.cs @@ -1,6 +1,6 @@ namespace PortProxyGUI { - partial class NewProxy + partial class SetProxyForm { /// /// Required designer variable. @@ -28,14 +28,14 @@ /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NewProxy)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SetProxyForm)); this.label1 = new System.Windows.Forms.Label(); this.textBox_listenOn = new System.Windows.Forms.TextBox(); this.label2 = new System.Windows.Forms.Label(); this.textBox_connectTo = new System.Windows.Forms.TextBox(); this.textBox_connectPort = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); + this.button_submit = new System.Windows.Forms.Button(); this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.textBox_listenPort = new System.Windows.Forms.TextBox(); @@ -72,12 +72,12 @@ resources.ApplyResources(this.label3, "label3"); this.label3.Name = "label3"; // - // button1 + // button_submit // - resources.ApplyResources(this.button1, "button1"); - this.button1.Name = "button1"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + resources.ApplyResources(this.button_submit, "button_submit"); + this.button_submit.Name = "button_submit"; + this.button_submit.UseVisualStyleBackColor = true; + this.button_submit.Click += new System.EventHandler(this.button_submit_Click); // // label4 // @@ -106,16 +106,16 @@ resources.GetString("comboBox_type.Items4")}); this.comboBox_type.Name = "comboBox_type"; // - // NewProxy + // SetProxyForm // - this.AcceptButton = this.button1; + this.AcceptButton = this.button_submit; resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.comboBox_type); this.Controls.Add(this.textBox_listenPort); this.Controls.Add(this.label5); this.Controls.Add(this.label4); - this.Controls.Add(this.button1); + this.Controls.Add(this.button_submit); this.Controls.Add(this.label3); this.Controls.Add(this.textBox_connectPort); this.Controls.Add(this.textBox_connectTo); @@ -125,10 +125,10 @@ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.MaximizeBox = false; this.MinimizeBox = false; - this.Name = "NewProxy"; + this.Name = "SetProxyForm"; this.TopMost = true; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.NewProxy_FormClosing); - this.Load += new System.EventHandler(this.NewProxy_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SetProxyForm_FormClosing); + this.Load += new System.EventHandler(this.SetProxyForm_Load); this.ResumeLayout(false); this.PerformLayout(); @@ -142,7 +142,7 @@ private System.Windows.Forms.TextBox textBox_connectTo; private System.Windows.Forms.TextBox textBox_connectPort; private System.Windows.Forms.Label label3; - private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button_submit; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label5; private System.Windows.Forms.TextBox textBox_listenPort; diff --git a/PortProxyGUI/NewProxy.cs b/PortProxyGUI/SetProxyForm.cs similarity index 52% rename from PortProxyGUI/NewProxy.cs rename to PortProxyGUI/SetProxyForm.cs index a8814c0..39f5c2c 100644 --- a/PortProxyGUI/NewProxy.cs +++ b/PortProxyGUI/SetProxyForm.cs @@ -6,21 +6,48 @@ using System.Windows.Forms; namespace PortProxyGUI { - public partial class NewProxy : Form + public partial class SetProxyForm : Form { public readonly PortProxyGUI PortProxyGUI; - private string AutoString { get; } + public bool UpdateMode { get; private set; } + private string AutoTypeString { get; } - public NewProxy(PortProxyGUI portProxyGUI) + public SetProxyForm(PortProxyGUI portProxyGUI) { PortProxyGUI = portProxyGUI; InitializeComponent(); - AutoString = comboBox_type.Text = comboBox_type.Items.OfType().First(); + AutoTypeString = comboBox_type.Text = comboBox_type.Items.OfType().First(); } - private void AddPortProxy(string type, string listenOn, string listenPort, string connectTo, string connectPort) + public void UseNormalMode() { - var output = CmdRunner.Execute($"netsh interface portproxy add {type} listenaddress={listenOn} listenport={listenPort} connectaddress={connectTo} connectport={connectPort}"); + comboBox_type.Enabled = true; + textBox_listenOn.Enabled = true; + textBox_listenPort.Enabled = true; + comboBox_type.Text = AutoTypeString; + textBox_listenOn.Text = "*"; + textBox_listenPort.Text = ""; + textBox_connectTo.Text = ""; + textBox_connectPort.Text = ""; + UpdateMode = false; + } + + public void UseUpdateMode(string type, string listenOn, string listenPort, string connectTo, string connectPort) + { + comboBox_type.Enabled = false; + textBox_listenOn.Enabled = false; + textBox_listenPort.Enabled = false; + comboBox_type.Text = type; + textBox_listenOn.Text = listenOn; + textBox_listenPort.Text = listenPort; + textBox_connectTo.Text = connectTo; + textBox_connectPort.Text = connectPort; + UpdateMode = true; + } + + private void SetPortProxy(string type, string action, string listenOn, string listenPort, string connectTo, string connectPort) + { + var output = CmdRunner.Execute($"netsh interface portproxy {action} {type} listenaddress={listenOn} listenport={listenPort} connectaddress={connectTo} connectport={connectPort}"); Invoke((Action)(() => PortProxyGUI.RefreshProxyList())); } @@ -40,7 +67,7 @@ namespace PortProxyGUI return $"{from}to{to}"; } - private void button1_Click(object sender, EventArgs e) + private void button_submit_Click(object sender, EventArgs e) { var type = comboBox_type.Text.Trim(); var listenOn = textBox_listenOn.Text.Trim().ToLower(); @@ -60,7 +87,7 @@ namespace PortProxyGUI return; } - if (type == AutoString) type = GetPassType(listenOn, connectTo); + if (type == AutoTypeString) type = GetPassType(listenOn, connectTo); if (!new[] { "v4tov4", "v4tov6", "v6tov4", "v6tov6" }.Contains(type)) { @@ -68,16 +95,19 @@ namespace PortProxyGUI return; } - AddPortProxy(type, listenOn, listenPort, connectTo, connectPort); + SetPortProxy(type, UpdateMode ? "set" : "add", listenOn, listenPort, connectTo, connectPort); + Close(); } - private void NewProxy_Load(object sender, EventArgs e) + private void SetProxyForm_Load(object sender, EventArgs e) { + Top = PortProxyGUI.Top + (PortProxyGUI.Height - Height) / 2; + Left = PortProxyGUI.Left + (PortProxyGUI.Width - Width) / 2; } - private void NewProxy_FormClosing(object sender, FormClosingEventArgs e) + private void SetProxyForm_FormClosing(object sender, FormClosingEventArgs e) { - PortProxyGUI.NewProxyForm = null; + PortProxyGUI.SetProxyForm = null; } } diff --git a/PortProxyGUI - NET/NewProxy.resx b/PortProxyGUI/SetProxyForm.resx similarity index 99% rename from PortProxyGUI - NET/NewProxy.resx rename to PortProxyGUI/SetProxyForm.resx index 2b93f0b..c6e8f82 100644 --- a/PortProxyGUI - NET/NewProxy.resx +++ b/PortProxyGUI/SetProxyForm.resx @@ -285,28 +285,28 @@ 5 - + 227, 62 - + 74, 22 - + 6 - - Add + + Set - - button1 + + button_submit - + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + $this - + 4 @@ -2603,13 +2603,13 @@ 3, 2, 3, 2 - CenterScreen + Manual - New Proxy + Set Proxy - NewProxy + SetProxyForm System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/PortProxyGUI - NET/NewProxy.zh-CN.resx b/PortProxyGUI/SetProxyForm.zh-CN.resx similarity index 99% rename from PortProxyGUI - NET/NewProxy.zh-CN.resx rename to PortProxyGUI/SetProxyForm.zh-CN.resx index 27fe0b0..2dbaeb4 100644 --- a/PortProxyGUI - NET/NewProxy.zh-CN.resx +++ b/PortProxyGUI/SetProxyForm.zh-CN.resx @@ -201,8 +201,8 @@ 5 - - 添加 + + 设置 button1 @@ -283,7 +283,7 @@ 0 - 新建映射 + 设置映射 NewProxy diff --git a/docs/ui.png b/docs/ui.png index 28c48c72f735e351d4dc159746da2c3456bd0242..3e4af76019f10e629915ba27cce6d48cac44843b 100644 GIT binary patch literal 12787 zcmeHucT|(xyJkEVj-nzWf+8Sr01+vQNH3yv0TmIYTEWnwlu!ah1x2Jwla3IIQlb)y zgn)t+L0WuxJ0BXAuy{=~~l^=dT5j0CHfRsLhj~OUnV<4&IC0 z!Ef+*N82Aa-#;-jx^?MK7l~7nKTqWF7s^I;q9XrPx}}CnC?qHxI25_p;8hx5ur47d zTjs={rzKuZdH50Aj*bu$&51l>cebh2t=P}uc&4cW;^88e*AvO<0~dw5Qvck0D%ZU z+v-f3g6iFBe2ezT2w2QrZ3y8^4^?@}Z*1ERd3?5$Q18j@cs2ud@SWCMAXIRgExHe} zUvGox=S@Mm4{{n(yQ$SISP*CY39+iqZbga*0@>3^pj1rXPmtDH@z8sSHXa$E&kVsD z99PD9Ai4Mb%j~k~WNVksK88s-j)CwW2_Zh;H!syubV*}$BGKy8OdhQ2QAQ_0cSZnN zdn)T{pzRLLnZZ_ z?K>-MJ?KiRw8E(7SD)1EdFvlG >t!;d?0LbEy+>%m^?5ftJJ^7aO=H_y@bFJ@N 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