Compare commits

..

4 Commits

Author SHA1 Message Date
Faryan Rezagholi
0b944c4222 added lithuanian language dummy file (copy from default one) as a template to be translated #878 2019-09-02 18:33:10 +02:00
David Sparer
11abc789a0 fixed nunit runner path in publish script 2019-09-02 10:20:41 -05:00
David Sparer
15e2cdaad0 release date set in changelog 2019-09-02 10:03:01 -05:00
David Sparer
10b6973f0d updated changelog and bumped minor version 2019-09-02 09:59:21 -05:00
52 changed files with 936 additions and 2486 deletions

View File

@@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [1.77.1] - 2019-09-02
### Added ### Added
- #1512: Added option to close panel from right click menu - #1512: Added option to close panel from right click menu
- #1434: Revised sort button in connection tree to be able to sort in both orders - #1434: Revised sort button in connection tree to be able to sort in both orders
@@ -11,13 +11,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- #1385: Added option to start mRemoteNG minimized - #1385: Added option to start mRemoteNG minimized
- #826: Allow selecting RDP version to use when connecting - #826: Allow selecting RDP version to use when connecting
### Changed ### Changed
- #1544: Improved Polish translations
- #1518: Inheritance is no longer automatically enabled when importing nodes from Active Directory
- #1468: Improved mRemoteNG startup time - #1468: Improved mRemoteNG startup time
- #1443: Chinese (simplified) translation improvements - #1443: Chinese (simplified) translation improvements
- #1437: Norwegian translation improvements - #1437: Norwegian translation improvements
- #1378: Hyperlinks embedded within mRemoteNG now open in the system default browser
- #1239: Increased default key derivation function (KDF) iterations from 1000 to 10000 - #1239: Increased default key derivation function (KDF) iterations from 1000 to 10000
- #718: Moved port property from 'protocol' to 'connection' section - #718: Moved port property from 'protocol' to 'connection' section
- Moved most RDP enums outside of the RDP protocol class. Scripts which reference these enums will need to be updated. - Moved most RDP enums outside of the RDP protocol class. Scripts which reference these enums will need to be updated.
- Removed the "Automatically get session info" from the advanced options screen since it is no longer used.
### Fixed ### Fixed
- #1505: About screen now better follows theme colors
- #1493: Updated database setup scripts for MSSQL and MySQL
- #1470: The "Favorite" setting is now properly saved in the local connection settings file (not saved in database)
- #1447: Exception occurs when resetting layout - #1447: Exception occurs when resetting layout
- #1439: Searching in hosts tree loses first keystroke - #1439: Searching in hosts tree loses first keystroke
- #1428: Fixed a rare error when checking for FIPS - #1428: Fixed a rare error when checking for FIPS

View File

@@ -2,7 +2,7 @@ node('windows') {
def jobDir = pwd() def jobDir = pwd()
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\"" def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe" def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe" def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.10.0\\tools\\nunit3-console.exe"
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe" def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
def testResultFilePrefix = "TestResult" def testResultFilePrefix = "TestResult"
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml" def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"

View File

@@ -12,7 +12,7 @@ namespace mRemoteNGTests.Connection.Protocol
{ {
public class IntegratedProgramTests public class IntegratedProgramTests
{ {
private readonly ExternalTool _extTool = new ExternalTool(new ConnectionInitiator(new ProtocolFactory())) private readonly ExternalTool _extTool = new ExternalTool
{ {
DisplayName = "notepad", DisplayName = "notepad",
FileName = @"%windir%\system32\notepad.exe", FileName = @"%windir%\system32\notepad.exe",
@@ -50,7 +50,7 @@ namespace mRemoteNGTests.Connection.Protocol
private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut) private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut)
{ {
var connectionWindow = new ConnectionWindow(new DockContent(), new ConnectionInitiator(new ProtocolFactory())); var connectionWindow = new ConnectionWindow(new DockContent());
var connectionInfo = new ConnectionInfo {ExtApp = extAppName, Protocol = ProtocolType.IntApp}; var connectionInfo = new ConnectionInfo {ExtApp = extAppName, Protocol = ProtocolType.IntApp};
return new InterfaceControl(connectionWindow, sut, connectionInfo); return new InterfaceControl(connectionWindow, sut, connectionInfo);
} }

View File

@@ -1,6 +1,4 @@
using mRemoteNG.Connection; using NUnit.Framework;
using mRemoteNG.Connection.Protocol;
using NUnit.Framework;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
namespace mRemoteNGTests.UI.Forms namespace mRemoteNGTests.UI.Forms
@@ -17,7 +15,7 @@ namespace mRemoteNGTests.UI.Forms
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_optionsForm = new FrmOptions(new ConnectionInitiator(new ProtocolFactory())); _optionsForm = new FrmOptions();
_optionsForm.Show(); _optionsForm.Show();
} }

View File

@@ -1,6 +1,4 @@
using System.Threading; using System.Threading;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
using NUnit.Framework; using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
@@ -15,7 +13,7 @@ namespace mRemoteNGTests.UI.Window
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_connectionTreeWindow = new ConnectionTreeWindow(new DockContent(), new ConnectionInitiator(new ProtocolFactory())); _connectionTreeWindow = new ConnectionTreeWindow(new DockContent());
} }
[TearDown] [TearDown]

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
using mRemoteNG.Config.Putty; using mRemoteNG.Config.Putty;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Credential; using mRemoteNG.Credential;

View File

@@ -1,5 +1,4 @@
using System; using System;
using mRemoteNG.Connection;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.UI; using mRemoteNG.UI;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
@@ -21,7 +20,7 @@ namespace mRemoteNG.App
internal static ConnectionTreeWindow TreeForm internal static ConnectionTreeWindow TreeForm
{ {
get => _treeForm ?? (_treeForm = new ConnectionTreeWindow(ConnectionInitiator)); get => _treeForm ?? (_treeForm = new ConnectionTreeWindow());
set => _treeForm = value; set => _treeForm = value;
} }
@@ -30,7 +29,6 @@ namespace mRemoteNG.App
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow(); internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow(); private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow(); internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
internal static IConnectionInitiator ConnectionInitiator { get; set; }
public static void Show(WindowType windowType) public static void Show(WindowType windowType)
@@ -52,7 +50,7 @@ namespace mRemoteNG.App
_adimportForm.Show(dockPanel); _adimportForm.Show(dockPanel);
break; break;
case WindowType.Options: case WindowType.Options:
using (var optionsForm = new FrmOptions(ConnectionInitiator)) using (var optionsForm = new FrmOptions())
{ {
optionsForm.ShowDialog(dockPanel); optionsForm.ShowDialog(dockPanel);
} }
@@ -75,7 +73,7 @@ namespace mRemoteNG.App
break; break;
case WindowType.ExternalApps: case WindowType.ExternalApps:
if (_externalappsForm == null || _externalappsForm.IsDisposed) if (_externalappsForm == null || _externalappsForm.IsDisposed)
_externalappsForm = new ExternalToolsWindow(ConnectionInitiator); _externalappsForm = new ExternalToolsWindow();
_externalappsForm.Show(dockPanel); _externalappsForm.Show(dockPanel);
break; break;
case WindowType.PortScan: case WindowType.PortScan:

View File

@@ -4,7 +4,6 @@ using mRemoteNG.App.Info;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using System.IO; using System.IO;
using System.Xml; using System.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.UI.Controls; using mRemoteNG.UI.Controls;
@@ -14,14 +13,12 @@ namespace mRemoteNG.Config.Settings
public class ExternalAppsLoader public class ExternalAppsLoader
{ {
private readonly FrmMain _mainForm; private readonly FrmMain _mainForm;
private readonly IConnectionInitiator _connectionInitiator;
private readonly MessageCollector _messageCollector; private readonly MessageCollector _messageCollector;
private readonly ExternalToolsToolStrip _externalToolsToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip;
public ExternalAppsLoader(FrmMain mainForm, public ExternalAppsLoader(FrmMain mainForm,
MessageCollector messageCollector, MessageCollector messageCollector,
ExternalToolsToolStrip externalToolsToolStrip, ExternalToolsToolStrip externalToolsToolStrip)
IConnectionInitiator connectionInitiator)
{ {
if (mainForm == null) if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm)); throw new ArgumentNullException(nameof(mainForm));
@@ -33,7 +30,6 @@ namespace mRemoteNG.Config.Settings
_mainForm = mainForm; _mainForm = mainForm;
_messageCollector = messageCollector; _messageCollector = messageCollector;
_externalToolsToolStrip = externalToolsToolStrip; _externalToolsToolStrip = externalToolsToolStrip;
_connectionInitiator = connectionInitiator;
} }
@@ -75,7 +71,7 @@ namespace mRemoteNG.Config.Settings
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes) foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
{ {
var extA = new ExternalTool(_connectionInitiator) var extA = new ExternalTool
{ {
DisplayName = xEl.Attributes["DisplayName"].Value, DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value, FileName = xEl.Attributes["FileName"].Value,

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
@@ -7,7 +7,6 @@ using System.Threading;
using System.Globalization; using System.Globalization;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
using mRemoteNG.Connection;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.UI.Controls; using mRemoteNG.UI.Controls;
@@ -24,19 +23,16 @@ namespace mRemoteNG.Config.Settings
private readonly QuickConnectToolStrip _quickConnectToolStrip; private readonly QuickConnectToolStrip _quickConnectToolStrip;
private readonly ExternalToolsToolStrip _externalToolsToolStrip; private readonly ExternalToolsToolStrip _externalToolsToolStrip;
private readonly MultiSshToolStrip _multiSshToolStrip; private readonly MultiSshToolStrip _multiSshToolStrip;
private readonly IConnectionInitiator _connectionInitiator;
private FrmMain MainForm { get; } private FrmMain MainForm { get; }
public SettingsLoader( public SettingsLoader(FrmMain mainForm,
FrmMain mainForm, MessageCollector messageCollector,
IConnectionInitiator connectionInitiator, QuickConnectToolStrip quickConnectToolStrip,
MessageCollector messageCollector, ExternalToolsToolStrip externalToolsToolStrip,
QuickConnectToolStrip quickConnectToolStrip, MultiSshToolStrip multiSshToolStrip,
ExternalToolsToolStrip externalToolsToolStrip, MenuStrip mainMenu)
MultiSshToolStrip multiSshToolStrip,
MenuStrip mainMenu)
{ {
if (mainForm == null) if (mainForm == null)
throw new ArgumentNullException(nameof(mainForm)); throw new ArgumentNullException(nameof(mainForm));
@@ -57,8 +53,7 @@ namespace mRemoteNG.Config.Settings
_externalToolsToolStrip = externalToolsToolStrip; _externalToolsToolStrip = externalToolsToolStrip;
_multiSshToolStrip = multiSshToolStrip; _multiSshToolStrip = multiSshToolStrip;
_mainMenu = mainMenu; _mainMenu = mainMenu;
_connectionInitiator = connectionInitiator; _externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip, _connectionInitiator);
} }
#region Public Methods #region Public Methods
@@ -161,10 +156,10 @@ namespace mRemoteNG.Config.Settings
MainForm.Fullscreen.Value = true; MainForm.Fullscreen.Value = true;
} }
private void SetShowSystemTrayIcon() private static void SetShowSystemTrayIcon()
{ {
if (mRemoteNG.Settings.Default.ShowSystemTrayIcon) if (mRemoteNG.Settings.Default.ShowSystemTrayIcon)
Runtime.NotificationAreaIcon = new NotificationAreaIcon(_connectionInitiator); Runtime.NotificationAreaIcon = new NotificationAreaIcon();
} }
private static void SetPuttyPath() private static void SetPuttyPath()

View File

@@ -5,6 +5,7 @@ using mRemoteNG.App;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Tabs; using mRemoteNG.UI.Tabs;
@@ -16,15 +17,10 @@ namespace mRemoteNG.Connection
{ {
public class ConnectionInitiator : IConnectionInitiator public class ConnectionInitiator : IConnectionInitiator
{ {
private readonly ProtocolFactory _protocolFactory; private readonly PanelAdder _panelAdder = new PanelAdder();
private readonly List<ProtocolBase> _activeConnections = new List<ProtocolBase>(); private readonly List<string> _activeConnections = new List<string>();
public IEnumerable<ProtocolBase> ActiveConnections => _activeConnections; public IEnumerable<string> ActiveConnections => _activeConnections;
public ConnectionInitiator(ProtocolFactory protocolFactory)
{
_protocolFactory = protocolFactory;
}
public bool SwitchToOpenConnection(ConnectionInfo connectionInfo) public bool SwitchToOpenConnection(ConnectionInfo connectionInfo)
{ {
@@ -37,8 +33,6 @@ namespace mRemoteNG.Connection
return true; return true;
} }
public void OpenConnection( public void OpenConnection(
ContainerInfo containerInfo, ContainerInfo containerInfo,
ConnectionInfo.Force force = ConnectionInfo.Force.None, ConnectionInfo.Force force = ConnectionInfo.Force.None,
@@ -81,7 +75,8 @@ namespace mRemoteNG.Connection
return; return;
} }
var newProtocol = _protocolFactory.CreateProtocol(connectionInfo); var protocolFactory = new ProtocolFactory();
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
var connectionPanel = SetConnectionPanel(connectionInfo, force); var connectionPanel = SetConnectionPanel(connectionInfo, force);
if (string.IsNullOrEmpty(connectionPanel)) return; if (string.IsNullOrEmpty(connectionPanel)) return;
@@ -99,7 +94,6 @@ namespace mRemoteNG.Connection
return; return;
} }
OnConnectionStarting(newProtocol.InterfaceControl.Info, newProtocol);
if (newProtocol.Connect() == false) if (newProtocol.Connect() == false)
{ {
newProtocol.Close(); newProtocol.Close();
@@ -107,7 +101,7 @@ namespace mRemoteNG.Connection
} }
connectionInfo.OpenConnections.Add(newProtocol); connectionInfo.OpenConnections.Add(newProtocol);
_activeConnections.Add(newProtocol); _activeConnections.Add(connectionInfo.ConstantID);
FrmMain.Default.SelectedConnection = connectionInfo; FrmMain.Default.SelectedConnection = connectionInfo;
} }
catch (Exception ex) catch (Exception ex)
@@ -147,14 +141,14 @@ namespace mRemoteNG.Connection
return null; return null;
} }
private string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force) private static string SetConnectionPanel(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{ {
if (connectionInfo.Panel != "" && if (connectionInfo.Panel != "" &&
!force.HasFlag(ConnectionInfo.Force.OverridePanel) && !force.HasFlag(ConnectionInfo.Force.OverridePanel) &&
!Settings.Default.AlwaysShowPanelSelectionDlg) !Settings.Default.AlwaysShowPanelSelectionDlg)
return connectionInfo.Panel; return connectionInfo.Panel;
var frmPnl = new FrmChoosePanel(this); var frmPnl = new FrmChoosePanel();
return frmPnl.ShowDialog() == DialogResult.OK return frmPnl.ShowDialog() == DialogResult.OK
? frmPnl.Panel ? frmPnl.Panel
: null; : null;
@@ -165,7 +159,7 @@ namespace mRemoteNG.Connection
var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel) as ConnectionWindow; var connectionForm = conForm ?? Runtime.WindowList.FromString(connectionPanel) as ConnectionWindow;
if (connectionForm == null) if (connectionForm == null)
connectionForm = new PanelAdder(this).AddPanel(connectionPanel); connectionForm = _panelAdder.AddPanel(connectionPanel);
else else
connectionForm.Show(FrmMain.Default.pnlDock); connectionForm.Show(FrmMain.Default.pnlDock);
@@ -229,11 +223,11 @@ namespace mRemoteNG.Connection
} }
Runtime.MessageCollector.AddMessage(msgClass, Runtime.MessageCollector.AddMessage(msgClass,
string.Format( string.Format(
Language.strProtocolEventDisconnected, Language.strProtocolEventDisconnected,
disconnectedMessage, disconnectedMessage,
prot.InterfaceControl.Info.Hostname, prot.InterfaceControl.Info.Hostname,
prot.InterfaceControl.Info.Protocol.ToString())); prot.InterfaceControl.Info.Protocol.ToString()));
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -262,8 +256,8 @@ namespace mRemoteNG.Connection
prot.InterfaceControl.Info.Protocol, prot.InterfaceControl.Info.Protocol,
Environment.UserName)); Environment.UserName));
prot.InterfaceControl.Info.OpenConnections.Remove(prot); prot.InterfaceControl.Info.OpenConnections.Remove(prot);
if (_activeConnections.Contains(prot)) if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID))
_activeConnections.Remove(prot); _activeConnections.Remove(prot.InterfaceControl.Info.ConstantID);
if (prot.InterfaceControl.Info.PostExtApp == "") return; if (prot.InterfaceControl.Info.PostExtApp == "") return;
var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp); var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
@@ -275,7 +269,7 @@ namespace mRemoteNG.Connection
} }
} }
private void Prot_Event_Connected(object sender) private static void Prot_Event_Connected(object sender)
{ {
var prot = (ProtocolBase)sender; var prot = (ProtocolBase)sender;
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnectionEventConnected, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnectionEventConnected,
@@ -308,11 +302,5 @@ namespace mRemoteNG.Connection
} }
#endregion #endregion
public event EventHandler<ConnectionStartingEvent> ConnectionStarting;
protected virtual void OnConnectionStarting(ConnectionInfo connectionInfo, ProtocolBase protocolBase)
{
ConnectionStarting?.Invoke(this, new ConnectionStartingEvent(connectionInfo, protocolBase));
}
} }
} }

View File

@@ -1,18 +0,0 @@
using System;
using mRemoteNG.Connection.Protocol;
namespace mRemoteNG.Connection
{
[Serializable]
public class ConnectionStartingEvent : EventArgs
{
public ConnectionInfo ConnectionInfo { get; }
public ProtocolBase Protocol { get; }
public ConnectionStartingEvent(ConnectionInfo connectionInfo, ProtocolBase protocol)
{
ConnectionInfo = connectionInfo;
Protocol = protocol;
}
}
}

View File

@@ -1,6 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container; using mRemoteNG.Container;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -8,7 +6,7 @@ namespace mRemoteNG.Connection
{ {
public interface IConnectionInitiator public interface IConnectionInitiator
{ {
IEnumerable<ProtocolBase> ActiveConnections { get; } IEnumerable<string> ActiveConnections { get; }
void OpenConnection( void OpenConnection(
ContainerInfo containerInfo, ContainerInfo containerInfo,
@@ -21,7 +19,5 @@ namespace mRemoteNG.Connection
ConnectionWindow conForm = null); ConnectionWindow conForm = null);
bool SwitchToOpenConnection(ConnectionInfo connectionInfo); bool SwitchToOpenConnection(ConnectionInfo connectionInfo);
event EventHandler<ConnectionStartingEvent> ConnectionStarting;
} }
} }

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using System; using System;
using System.Drawing; using System.Drawing;
@@ -25,8 +25,6 @@ namespace mRemoteNG.Connection
Location = new Point(0, 0); Location = new Point(0, 0);
Size = Parent.Size; Size = Parent.Size;
Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
GotFocus += OnGotFocus;
LostFocus += OnLostFocus;
InitializeComponent(); InitializeComponent();
} }
catch (Exception ex) catch (Exception ex)
@@ -37,16 +35,6 @@ namespace mRemoteNG.Connection
} }
} }
private void OnLostFocus(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"InterfaceControl lost focus '{Info.Name}'");
}
private void OnGotFocus(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"InterfaceControl gained focus '{Info.Name}'");
}
public static InterfaceControl FindInterfaceControl(DockPanel DockPnl) public static InterfaceControl FindInterfaceControl(DockPanel DockPnl)
{ {
if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null; if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null;

View File

@@ -1,120 +0,0 @@
using System;
using System.Diagnostics;
using mRemoteNG.App;
using mRemoteNG.Messages;
namespace mRemoteNG.Connection.Protocol
{
public abstract class ExternalProcessProtocolBase : ProtocolBase, IFocusable
{
private IntPtr _winEventHook;
private NativeMethods.WinEventDelegate _setForegroundDelegate;
private bool _hasFocus;
public override bool IsExternalProcess { get; } = true;
protected Process ProtocolProcess { get; set; }
protected IntPtr ProcessHandle { get; set; }
public bool HasFocus
{
get => _hasFocus;
private set
{
if (_hasFocus == value)
return;
_hasFocus = value;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
string.Format("External protocol window set to {0}. name:'{1}', protocol:'{2}', pid:{3}, hwnd:{4}",
_hasFocus ? "foreground" : "background",
InterfaceControl.Info.Name,
InterfaceControl.Info.Protocol,
ProtocolProcess.Id,
ProcessHandle));
OnFocusChanged();
}
}
public int ThreadId => (int)NativeMethods.GetWindowThreadProcessId(ProcessHandle, IntPtr.Zero);
public override bool Connect()
{
_setForegroundDelegate = OnWinEventSetForeground;
_winEventHook = NativeMethods.SetWinEventHook(
NativeMethods.EVENT_SYSTEM_FOREGROUND,
NativeMethods.EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero,
_setForegroundDelegate,
/*Convert.ToUInt32(ProtocolProcess.Id)*/0,
0,
NativeMethods.WINEVENT_OUTOFCONTEXT);
return base.Connect();
}
public override void Close()
{
if (NativeMethods.UnhookWinEvent(_winEventHook))
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Successfully unhooked WinEvent listener from '{InterfaceControl.Info.Name}'");
}
else
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Failed to unhook WinEvent listener from '{InterfaceControl.Info.Name}'");
}
base.Close();
}
public override void Focus()
{
FocusChildProcessWindow();
}
private void FocusChildProcessWindow()
{
if (NativeMethods.GetForegroundWindow() == ProcessHandle)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Process already focused - do nothing");
return;
}
var setForegroundSuccessful = NativeMethods.SetForegroundWindow(ProcessHandle);
if (!setForegroundSuccessful)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
"Failed to set external protocol window to foreground. " +
$"name:'{InterfaceControl.Info.Name}', " +
$"protocol:'{InterfaceControl.Info.Protocol}', " +
$"pid:{ProtocolProcess.Id}, " +
$"hwnd:{ProcessHandle}");
}
}
/// <summary>
/// This callback will be called when the external process window managed by
/// this protocol is brought to the foreground.
/// </summary>
/// <param name="hWinEventHook"></param>
/// <param name="eventType"></param>
/// <param name="hwnd"></param>
/// <param name="idObject"></param>
/// <param name="idChild"></param>
/// <param name="dwEventThread"></param>
/// <param name="dwmsEventTime"></param>
void OnWinEventSetForeground(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
HasFocus = hwnd == ProcessHandle;
}
public event EventHandler FocusChanged;
protected virtual void OnFocusChanged()
{
FocusChanged?.Invoke(this, EventArgs.Empty);
}
}
}

View File

@@ -1,11 +0,0 @@
using System;
namespace mRemoteNG.Connection.Protocol
{
public interface IFocusable
{
bool HasFocus { get; }
void Focus();
event EventHandler FocusChanged;
}
}

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Threading; using System.Threading;
@@ -9,7 +9,7 @@ using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol namespace mRemoteNG.Connection.Protocol
{ {
public class IntegratedProgram : ExternalProcessProtocolBase public class IntegratedProgram : ProtocolBase
{ {
#region Private Fields #region Private Fields

View File

@@ -63,12 +63,6 @@ namespace mRemoteNG.Connection.Protocol
public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000); public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000);
protected ReconnectGroup ReconnectGroup; protected ReconnectGroup ReconnectGroup;
/// <summary>
/// Whether this protocol runs as a thread within the main process or if
/// it is an external process that is running as a child process.
/// </summary>
public virtual bool IsExternalProcess { get; } = false;
protected ProtocolBase(string name) protected ProtocolBase(string name)
{ {
Name = name; Name = name;
@@ -341,7 +335,8 @@ namespace mRemoteNG.Connection.Protocol
{ {
if (!disposing) return; if (!disposing) return;
tmrReconnect?.Dispose(); if(tmrReconnect != null)
tmrReconnect.Dispose();
} }
public void Dispose() public void Dispose()

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Security.SymmetricEncryption; using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools; using mRemoteNG.Tools;
@@ -14,22 +14,27 @@ using System.Windows.Forms;
namespace mRemoteNG.Connection.Protocol namespace mRemoteNG.Connection.Protocol
{ {
public class PuttyBase : ExternalProcessProtocolBase public class PuttyBase : ProtocolBase
{ {
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
private bool _isPuttyNg; private bool _isPuttyNg;
private readonly DisplayProperties _display = new DisplayProperties(); private readonly DisplayProperties _display = new DisplayProperties();
#region Public Properties #region Public Properties
protected Putty_Protocol PuttyProtocol { private get; set; } protected Putty_Protocol PuttyProtocol { private get; set; }
protected Putty_SSHVersion PuttySSHVersion { private get; set; } protected Putty_SSHVersion PuttySSHVersion { private get; set; }
public IntPtr PuttyHandle { get; set; }
private Process PuttyProcess { get; set; }
public static string PuttyPath { get; set; } public static string PuttyPath { get; set; }
public bool Focused public bool Focused
{ {
get { return NativeMethods.GetForegroundWindow() == ProcessHandle; } get { return NativeMethods.GetForegroundWindow() == PuttyHandle; }
} }
#endregion #endregion
@@ -49,40 +54,111 @@ namespace mRemoteNG.Connection.Protocol
{ {
try try
{ {
base.Connect(); _isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg;
var arguments = BuildPuttyCommandLineArguments(InterfaceControl.Info);
ProtocolProcess = new Process PuttyProcess = new Process
{ {
StartInfo = StartInfo =
{ {
UseShellExecute = false, UseShellExecute = false,
FileName = PuttyPath, FileName = PuttyPath
Arguments = arguments.ToString() }
},
EnableRaisingEvents = true
}; };
ProtocolProcess.Exited += ProcessExited; var arguments = new CommandLineArguments {EscapeForShell = false};
ProtocolProcess.Start(); arguments.Add("-load", InterfaceControl.Info.PuttySession);
ProtocolProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
if (!(InterfaceControl.Info is PuttySessionInfo))
{
arguments.Add("-" + PuttyProtocol);
if (PuttyProtocol == Putty_Protocol.ssh)
{
var username = "";
var password = "";
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Username))
{
username = InterfaceControl.Info.Username;
}
else
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (Settings.Default.EmptyCredentials)
{
case "windows":
username = Environment.UserName;
break;
case "custom":
username = Settings.Default.DefaultUsername;
break;
}
}
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password))
{
password = InterfaceControl.Info.Password;
}
else
{
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword,
Runtime.EncryptionKey);
}
}
arguments.Add("-" + (int)PuttySSHVersion);
if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials))
{
if (!string.IsNullOrEmpty(username))
{
arguments.Add("-l", username);
}
if (!string.IsNullOrEmpty(password))
{
arguments.Add("-pw", password);
}
}
}
arguments.Add("-P", InterfaceControl.Info.Port.ToString());
arguments.Add(InterfaceControl.Info.Hostname);
}
if (_isPuttyNg)
{
arguments.Add("-hwndparent", InterfaceControl.Handle.ToString());
}
PuttyProcess.StartInfo.Arguments = arguments.ToString();
PuttyProcess.EnableRaisingEvents = true;
PuttyProcess.Exited += ProcessExited;
PuttyProcess.Start();
PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount; var startTicks = Environment.TickCount;
while (ProcessHandle.ToInt32() == 0 & while (PuttyHandle.ToInt32() == 0 &
Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000) Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
{ {
if (_isPuttyNg) if (_isPuttyNg)
{ {
ProcessHandle = NativeMethods.FindWindowEx(InterfaceControl.Handle, new IntPtr(0), null, null); PuttyHandle = NativeMethods.FindWindowEx(
InterfaceControl.Handle, new IntPtr(0), null, null);
} }
else else
{ {
ProtocolProcess.Refresh(); PuttyProcess.Refresh();
ProcessHandle = ProtocolProcess.MainWindowHandle; PuttyHandle = PuttyProcess.MainWindowHandle;
} }
if (ProcessHandle.ToInt32() == 0) if (PuttyHandle.ToInt32() == 0)
{ {
Thread.Sleep(0); Thread.Sleep(0);
} }
@@ -90,20 +166,21 @@ namespace mRemoteNG.Connection.Protocol
if (!_isPuttyNg) if (!_isPuttyNg)
{ {
NativeMethods.SetParent(ProcessHandle, InterfaceControl.Handle); NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle);
} }
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true); Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyHandle, ProcessHandle), true); string.Format(Language.strPuttyHandle, PuttyHandle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyTitle, ProtocolProcess.MainWindowTitle), string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle),
true); true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyParentHandle, string.Format(Language.strPuttyParentHandle,
InterfaceControl.Parent.Handle), true); InterfaceControl.Parent.Handle), true);
Resize(this, new EventArgs()); Resize(this, new EventArgs());
base.Connect();
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@@ -115,102 +192,18 @@ namespace mRemoteNG.Connection.Protocol
} }
} }
private CommandLineArguments BuildPuttyCommandLineArguments(AbstractConnectionRecord connectionInfo)
{
var arguments = new CommandLineArguments { EscapeForShell = false };
arguments.Add("-load", connectionInfo.PuttySession);
if (!(connectionInfo is PuttySessionInfo))
{
arguments.Add("-" + PuttyProtocol);
if (PuttyProtocol == Putty_Protocol.ssh)
{
var username = "";
var password = "";
if (!string.IsNullOrEmpty(connectionInfo.Username))
{
username = connectionInfo.Username;
}
else
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (Settings.Default.EmptyCredentials)
{
case "windows":
username = Environment.UserName;
break;
case "custom":
username = Settings.Default.DefaultUsername;
break;
}
}
if (!string.IsNullOrEmpty(connectionInfo.Password))
{
password = connectionInfo.Password;
}
else
{
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword,
Runtime.EncryptionKey);
}
}
arguments.Add("-" + (int)PuttySSHVersion);
if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials))
{
if (!string.IsNullOrEmpty(username))
{
arguments.Add("-l", username);
}
if (!string.IsNullOrEmpty(password))
{
arguments.Add("-pw", password);
}
}
}
arguments.Add("-P", connectionInfo.Port.ToString());
arguments.Add(connectionInfo.Hostname);
}
_isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg;
if (_isPuttyNg)
{
arguments.Add("-hwndparent", InterfaceControl.Handle.ToString());
}
return arguments;
}
public override void Focus() public override void Focus()
{ {
//try try
//{ {
// if (NativeMethods.GetForegroundWindow() == PuttyHandle) NativeMethods.SetForegroundWindow(PuttyHandle);
// { }
// Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Putty window already focused, ignoring focus request '{InterfaceControl.Info.Name}' (pid:{PuttyProcess.Id})"); catch (Exception ex)
// return; {
// } Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
Language.strPuttyFocusFailed + Environment.NewLine + ex.Message,
// NativeMethods.SetForegroundWindow(PuttyHandle); true);
// Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Putty window focused '{InterfaceControl.Info.Name}' (pid:{PuttyProcess.Id})"); }
//}
//catch (Exception ex)
//{
// Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
// Language.strPuttyFocusFailed + Environment.NewLine + ex.Message,
// true);
//}
base.Focus();
} }
public override void Resize(object sender, EventArgs e) public override void Resize(object sender, EventArgs e)
@@ -223,14 +216,14 @@ namespace mRemoteNG.Connection.Protocol
if (_isPuttyNg) if (_isPuttyNg)
{ {
// PuTTYNG 0.70.0.1 and later doesn't have any window borders // PuTTYNG 0.70.0.1 and later doesn't have any window borders
NativeMethods.MoveWindow(ProcessHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true); NativeMethods.MoveWindow(PuttyHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true);
} }
else else
{ {
var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height); var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height);
var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width); var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width);
NativeMethods.MoveWindow(ProcessHandle, -scaledFrameBorderWidth, NativeMethods.MoveWindow(PuttyHandle, -scaledFrameBorderWidth,
-(SystemInformation.CaptionHeight + scaledFrameBorderHeight), -(SystemInformation.CaptionHeight + scaledFrameBorderHeight),
InterfaceControl.Width + scaledFrameBorderWidth * 2, InterfaceControl.Width + scaledFrameBorderWidth * 2,
InterfaceControl.Height + SystemInformation.CaptionHeight + InterfaceControl.Height + SystemInformation.CaptionHeight +
@@ -250,9 +243,9 @@ namespace mRemoteNG.Connection.Protocol
{ {
try try
{ {
if (ProtocolProcess.HasExited == false) if (PuttyProcess.HasExited == false)
{ {
ProtocolProcess.Kill(); PuttyProcess.Kill();
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -264,7 +257,7 @@ namespace mRemoteNG.Connection.Protocol
try try
{ {
ProtocolProcess.Dispose(); PuttyProcess.Dispose();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -280,8 +273,8 @@ namespace mRemoteNG.Connection.Protocol
{ {
try try
{ {
NativeMethods.PostMessage(ProcessHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, IntPtr.Zero); NativeMethods.PostMessage(PuttyHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, (IntPtr)0);
Focus(); NativeMethods.SetForegroundWindow(PuttyHandle);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -291,14 +284,6 @@ namespace mRemoteNG.Connection.Protocol
} }
} }
/// <summary>
/// Sends an individual key stroke to this PuTTY session.
/// </summary>
public void SendKeyStroke(int keyType, int keyData)
{
NativeMethods.PostMessage(ProcessHandle, keyType, new IntPtr(keyData), new IntPtr(0));
}
#endregion #endregion
#region Enums #region Enums

View File

@@ -1,9 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading; using System.Threading;
using System.Timers; using System.Timers;
using System.Windows.Forms; using System.Windows.Forms;
@@ -38,7 +35,6 @@ namespace mRemoteNG.Connection.Protocol.RDP
private readonly FrmMain _frmMain = FrmMain.Default; private readonly FrmMain _frmMain = FrmMain.Default;
protected virtual RdpVersion RdpProtocolVersion => RdpVersion.Rdc6; protected virtual RdpVersion RdpProtocolVersion => RdpVersion.Rdc6;
private AxHost AxHost => (AxHost)Control; private AxHost AxHost => (AxHost)Control;
private readonly NativeMethods.EnumWindowsProc _enumWindowsProc;
#region Properties #region Properties
@@ -105,7 +101,6 @@ namespace mRemoteNG.Connection.Protocol.RDP
{ {
_displayProperties = new DisplayProperties(); _displayProperties = new DisplayProperties();
tmrReconnect.Elapsed += tmrReconnect_Elapsed; tmrReconnect.Elapsed += tmrReconnect_Elapsed;
_enumWindowsProc = LpEnumFunc;
} }
#endregion #endregion
@@ -248,54 +243,17 @@ namespace mRemoteNG.Connection.Protocol.RDP
public override void Focus() public override void Focus()
{ {
var result = new List<IntPtr>();
var listHandle = GCHandle.Alloc(result);
try try
{ {
if (Control.ContainsFocus == false) if (Control.ContainsFocus == false)
{ {
//AxHost.Focus(); Control.Focus();
//AxHost.Select();
//AxHost.DoVerb(-1);
//AxHost.DoVerb(-4);
//AxHost.DoVerb(-5);
NativeMethods.EnumChildWindows(AxHost.Handle, _enumWindowsProc, GCHandle.ToIntPtr(listHandle));
if (result.Any())
{
NativeMethods.SetFocus(result[0]);
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP connection focused '{connectionInfo.Name}'");
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpFocusFailed, ex); Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpFocusFailed, ex);
} }
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
}
private bool LpEnumFunc(IntPtr hwnd, IntPtr lparam)
{
var gch = GCHandle.FromIntPtr(lparam);
var list = gch.Target as List<IntPtr>;
if (list == null)
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
var sb = new StringBuilder();
NativeMethods.GetClassName(hwnd, sb, 64);
if (sb.ToString().Equals("IHWindowClass"))
{
list.Add(hwnd);
return false;
}
return true;
} }
/// <summary> /// <summary>
@@ -714,9 +672,6 @@ namespace mRemoteNG.Connection.Protocol.RDP
_rdpClient.OnDisconnected += RDPEvent_OnDisconnected; _rdpClient.OnDisconnected += RDPEvent_OnDisconnected;
_rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode; _rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode;
_rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification; _rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification;
//_rdpClient.OnFocusReleased += direction => Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP control '{connectionInfo.Name}' released focus.");
//AxHost.GotFocus += (sender, args) => Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP control '{connectionInfo.Name}' received focus.");
//AxHost.LostFocus += (sender, args) => Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"RDP control '{connectionInfo.Name}' lost focus.");
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -793,7 +748,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
private void RdpClient_GotFocus(object sender, EventArgs e) private void RdpClient_GotFocus(object sender, EventArgs e)
{ {
//((ConnectionTab)Control.Parent.Parent).Focus(); ((ConnectionTab)Control.Parent.Parent).Focus();
} }
#endregion #endregion

View File

@@ -0,0 +1,23 @@
using mRemoteNG.Connection.Protocol;
namespace mRemoteNG.Connection
{
public class WebHelper
{
public static void GoToUrl(string url)
{
var connectionInfo = new ConnectionInfo();
connectionInfo.CopyFrom(DefaultConnectionInfo.Instance);
connectionInfo.Name = "";
connectionInfo.Hostname = url;
connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP;
connectionInfo.SetDefaultPort();
if (string.IsNullOrEmpty(connectionInfo.Panel))
connectionInfo.Panel = Language.strGeneral;
connectionInfo.IsQuickConnect = true;
var connectionInitiator = new ConnectionInitiator();
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
}
}
}

View File

@@ -6,7 +6,7 @@ namespace mRemoteNG.Messages.MessageWriters
{ {
public void Write(IMessage message) public void Write(IMessage message)
{ {
var textToPrint = $"[{message.Date.ToString("O")}] {message.Class}: {message.Text}"; var textToPrint = $"{message.Class}: {message.Text}";
Debug.Print(textToPrint); Debug.Print(textToPrint);
} }
} }

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below: // by using the '*' as shown below:
// <Assembly: AssemblyVersion("1.0.*")> // <Assembly: AssemblyVersion("1.0.*")>
[assembly: AssemblyVersion("1.77.0.*")] [assembly: AssemblyVersion("1.77.1.*")]
[assembly: NeutralResourcesLanguage("en")] [assembly: NeutralResourcesLanguage("en")]

View File

@@ -12,7 +12,7 @@ namespace mRemoteNG {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -2583,8 +2583,8 @@ namespace mRemoteNG {
[global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-" + [global::System.Configuration.DefaultSettingValueAttribute("cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,lt,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk," +
"TR,zh-CN,zh-TW")] "tr-TR,zh-CN,zh-TW")]
public string SupportedUICultures { public string SupportedUICultures {
get { get {
return ((string)(this["SupportedUICultures"])); return ((string)(this["SupportedUICultures"]));

View File

@@ -642,7 +642,7 @@
<Value Profile="(Default)">True</Value> <Value Profile="(Default)">True</Value>
</Setting> </Setting>
<Setting Name="SupportedUICultures" Type="System.String" Scope="Application"> <Setting Name="SupportedUICultures" Type="System.String" Scope="Application">
<Value Profile="(Default)">cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW</Value> <Value Profile="(Default)">cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,lt,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW</Value>
</Setting> </Setting>
<Setting Name="ThemingActive" Type="System.Boolean" Scope="User"> <Setting Name="ThemingActive" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value> <Value Profile="(Default)">True</Value>

View File

@@ -0,0 +1,345 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="PlaceSearchBarAboveConnectionTree" xml:space="preserve">
<value>Place search bar above connection tree</value>
</data>
<data name="strPropertyDescriptionColors" xml:space="preserve">
<value>Select the color quality to be used.</value>
</data>
<data name="strPropertyNameColors" xml:space="preserve">
<value>Colors</value>
</data>
<data name="strRDP16777216Colors" xml:space="preserve">
<value>16777216 Colors (24-bit)</value>
</data>
<data name="strRDP256Colors" xml:space="preserve">
<value>256 Colors (8-bit)</value>
</data>
<data name="strRDP32768Colors" xml:space="preserve">
<value>32768 Colors (15-bit)</value>
</data>
<data name="strRDP4294967296Colors" xml:space="preserve">
<value>16777216 Colors (32-bit)</value>
</data>
<data name="strRDP65536Colors" xml:space="preserve">
<value>65536 Colors (16-bit)</value>
</data>
<data name="strThemeDescriptionConfigPanelBackgroundColor" xml:space="preserve">
<value>The background color of the config panel.</value>
</data>
<data name="strThemeDescriptionConfigPanelCategoryTextColor" xml:space="preserve">
<value>The color of the category text in the config panel.</value>
</data>
<data name="strThemeDescriptionConfigPanelGridLineColor" xml:space="preserve">
<value>The color of the grid lines in the config panel</value>
</data>
<data name="strThemeDescriptionConfigPanelHelpBackgroundColor" xml:space="preserve">
<value>The background color of the help area of the config panel.</value>
</data>
<data name="strThemeDescriptionConfigPanelHelpTextColor" xml:space="preserve">
<value>The color of the text in the help area of the config panel.</value>
</data>
<data name="strThemeDescriptionConfigPanelTextColor" xml:space="preserve">
<value>The color of the text in the config panel.</value>
</data>
<data name="strThemeDescriptionConnectionsPanelBackgroundColor" xml:space="preserve">
<value>The background color of the connections panel.</value>
</data>
<data name="strThemeDescriptionConnectionsPanelTextColor" xml:space="preserve">
<value>The color of the text in the connections panel.</value>
</data>
<data name="strThemeDescriptionConnectionsPanelTreeLineColor" xml:space="preserve">
<value>The color of the tree lines in the connections panel.</value>
</data>
<data name="strThemeDescriptionMenuBackgroundColor" xml:space="preserve">
<value>The background color of the menus.</value>
</data>
<data name="strThemeDescriptionMenuTextColor" xml:space="preserve">
<value>The color of the text in the menus.</value>
</data>
<data name="strThemeDescriptionSearchBoxBackgroundColor" xml:space="preserve">
<value>The background color of the search box.</value>
</data>
<data name="strThemeDescriptionSearchBoxTextColor" xml:space="preserve">
<value>The color of the text in the search box.</value>
</data>
<data name="strThemeDescriptionSearchBoxTextPromptColor" xml:space="preserve">
<value>The color of the prompt text in the search box.</value>
</data>
<data name="strThemeDescriptionToolbarBackgroundColor" xml:space="preserve">
<value>The background color of the toolbars.</value>
</data>
<data name="strThemeDescriptionToolbarTextColor" xml:space="preserve">
<value>The color of the text in the toolbars.</value>
</data>
<data name="strThemeDescriptionWindowBackgroundColor" xml:space="preserve">
<value>The background color of the main window.</value>
</data>
<data name="strThemeNameConfigPanelBackgroundColor" xml:space="preserve">
<value>Config Panel Background Color</value>
</data>
<data name="strThemeNameConfigPanelCategoryTextColor" xml:space="preserve">
<value>Config Panel Category Text Color</value>
</data>
<data name="strThemeNameConfigPanelGridLineColor" xml:space="preserve">
<value>Config Panel Grid Line Color</value>
</data>
<data name="strThemeNameConfigPanelHelpBackgroundColor" xml:space="preserve">
<value>Config Panel Help Background Color</value>
</data>
<data name="strThemeNameConfigPanelHelpTextColor" xml:space="preserve">
<value>Config Panel Help Text Color</value>
</data>
<data name="strThemeNameConfigPanelTextColor" xml:space="preserve">
<value>Config Panel Text Color</value>
</data>
<data name="strThemeNameConnectionsPanelBackgroundColor" xml:space="preserve">
<value>Connections Panel Background Color</value>
</data>
<data name="strThemeNameConnectionsPanelTextColor" xml:space="preserve">
<value>Connections Panel Text Color</value>
</data>
<data name="strThemeNameConnectionsPanelTreeLineColor" xml:space="preserve">
<value>Connections Panel Tree Line Color</value>
</data>
<data name="strThemeNameMenuBackgroundColor" xml:space="preserve">
<value>Menu Background Color</value>
</data>
<data name="strThemeNameMenuTextColor" xml:space="preserve">
<value>Menu Text Color</value>
</data>
<data name="strThemeNameSearchBoxBackgroundColor" xml:space="preserve">
<value>Search Box Background Color</value>
</data>
<data name="strThemeNameSearchBoxTextColor" xml:space="preserve">
<value>Search Box Text Color</value>
</data>
<data name="strThemeNameSearchBoxTextPromptColor" xml:space="preserve">
<value>Search Box Text Prompt Color</value>
</data>
<data name="strThemeNameToolbarBackgroundColor" xml:space="preserve">
<value>Toolbar Background Color</value>
</data>
<data name="strThemeNameToolbarTextColor" xml:space="preserve">
<value>Toolbar Text Color</value>
</data>
<data name="strThemeNameWindowBackgroundColor" xml:space="preserve">
<value>Window Background Color</value>
</data>
<data name="strActiveDirectory" xml:space="preserve">
<value>Active Directory</value>
</data>
<data name="strErrorFipsPolicyIncompatible" xml:space="preserve">
<value>The Windows security setting, "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing", is enabled.
See the Microsoft Support article at http://support.microsoft.com/kb/811833 for more information.
{0} is not fully FIPS compliant. Click OK to proceed at your own discretion, or Cancel to Exit.</value>
</data>
<data name="strHttpGecko" xml:space="preserve">
<value>Gecko (Firefox)</value>
</data>
<data name="strHttpInternetExplorer" xml:space="preserve">
<value>Internet Explorer</value>
</data>
<data name="strImportLocationCommandButtons" xml:space="preserve">
<value>Under the root{0}{1}|Under the selected folder{0}{2}</value>
</data>
<data name="strNoInformation" xml:space="preserve">
<value>None</value>
</data>
<data name="strNone" xml:space="preserve">
<value>None</value>
</data>
<data name="strPropertyDescriptionRedirectClipboard" xml:space="preserve">
<value>Select whether clipboard should be shared.</value>
</data>
<data name="strPropertyNameRedirectClipboard" xml:space="preserve">
<value>Clipboard</value>
</data>
<data name="strOptionsThemeChangeWarning" xml:space="preserve">
<value>Warning: Restart is required to commit any theme configuration change.</value>
</data>
<data name="strIPRange" xml:space="preserve">
<value>Must Be Between 0 and 255</value>
</data>
<data name="strOutOfRange" xml:space="preserve">
<value>Out Of Range</value>
</data>
<data name="strDelete" xml:space="preserve">
<value>Delete...</value>
</data>
<data name="strReconnectAllConnections" xml:space="preserve">
<value>Reconnect All Connections</value>
</data>
<data name="strUltraVNCSingleClick" xml:space="preserve">
<value>UltraVNC SingleClick</value>
</data>
<data name="strMenuDisconnectOthers" xml:space="preserve">
<value>Disconnect All But This</value>
</data>
<data name="AutomaticReconnectError" xml:space="preserve">
<value>An error occurred while trying to reconnect to RDP host '{0}'</value>
</data>
<data name="ChangeConnectionResolutionError" xml:space="preserve">
<value>An error occurred while trying to change the connection resolution to host '{0}'</value>
</data>
<data name="StackTrace" xml:space="preserve">
<value>Stack trace</value>
</data>
<data name="ExceptionMessage" xml:space="preserve">
<value>Exception Message</value>
</data>
<data name="mRemoteNGUnhandledException" xml:space="preserve">
<value>mRemoteNG Unhandled Exception</value>
</data>
<data name="UnhandledExceptionOccured" xml:space="preserve">
<value>An unhandled exception has occurred</value>
</data>
<data name="ExceptionForcesmRemoteNGToClose" xml:space="preserve">
<value>This exception will force mRemoteNG to close</value>
</data>
<data name="strMenuCopyHostname" xml:space="preserve">
<value>Copy Hostname</value>
</data>
<data name="strPortScanSinglePort" xml:space="preserve">
<value>To scan a single port, select the "First Port" only.</value>
</data>
<data name="strTrackActiveConnectionInConnectionTree" xml:space="preserve">
<value>Track active connection in the connection tree</value>
</data>
<data name="strAlwaysShowConnectionTabs" xml:space="preserve">
<value>Always show connection tabs</value>
</data>
<data name="strReleaseChannel" xml:space="preserve">
<value>Release Channel</value>
</data>
<data name="strReleaseChannelExplanation" xml:space="preserve">
<value>Stable channel includes final releases only.
Beta channel includes Betas &amp; Release Candidates.
Development Channel includes Alphas, Betas &amp; Release Candidates.</value>
</data>
<data name="strButtonApply" xml:space="preserve">
<value>Apply</value>
</data>
<data name="strCategoryProxy" xml:space="preserve">
<value>Proxy</value>
</data>
</root>

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;

View File

@@ -16,7 +16,7 @@ namespace mRemoteNG.Tools
{ {
public class ExternalTool : INotifyPropertyChanged public class ExternalTool : INotifyPropertyChanged
{ {
private readonly IConnectionInitiator _connectionInitiator; private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private string _displayName; private string _displayName;
private string _fileName; private string _fileName;
private bool _waitForExit; private bool _waitForExit;
@@ -102,15 +102,12 @@ namespace mRemoteNG.Tools
#endregion #endregion
public ExternalTool( public ExternalTool(string displayName = "",
IConnectionInitiator connectionInitiator, string fileName = "",
string displayName = "", string arguments = "",
string fileName = "", string workingDir = "",
string arguments = "", bool runElevated = false)
string workingDir = "",
bool runElevated = false)
{ {
_connectionInitiator = connectionInitiator;
DisplayName = displayName; DisplayName = displayName;
FileName = fileName; FileName = fileName;
Arguments = arguments; Arguments = arguments;

View File

@@ -63,7 +63,7 @@ namespace mRemoteNG.Tools
foreach (PuttyBase proc in processHandlers) foreach (PuttyBase proc in processHandlers)
{ {
proc.SendKeyStroke(keyType, keyData); NativeMethods.PostMessage(proc.PuttyHandle, keyType, new IntPtr(keyData), new IntPtr(0));
} }
} }

View File

@@ -14,14 +14,13 @@ namespace mRemoteNG.Tools
private readonly NotifyIcon _nI; private readonly NotifyIcon _nI;
private readonly ContextMenuStrip _cMen; private readonly ContextMenuStrip _cMen;
private readonly ToolStripMenuItem _cMenCons; private readonly ToolStripMenuItem _cMenCons;
private readonly IConnectionInitiator _connectionInitiator; private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private static readonly FrmMain FrmMain = FrmMain.Default; private static readonly FrmMain FrmMain = FrmMain.Default;
public bool Disposed { get; private set; } public bool Disposed { get; private set; }
public NotificationAreaIcon(IConnectionInitiator connectionInitiator) public NotificationAreaIcon()
{ {
_connectionInitiator = connectionInitiator;
try try
{ {
_cMenCons = new ToolStripMenuItem _cMenCons = new ToolStripMenuItem

View File

@@ -26,7 +26,7 @@ namespace mRemoteNG.Tree
.Where(item => .Where(item =>
item.PleaseConnect && item.PleaseConnect &&
//ignore items that have already connected //ignore items that have already connected
_connectionInitiator.ActiveConnections.All(protocol => protocol.InterfaceControl.Info.ConstantID != item.ConstantID)); !_connectionInitiator.ActiveConnections.Contains(item.ConstantID));
foreach (var connectionInfo in previouslyOpenedConnections) foreach (var connectionInfo in previouslyOpenedConnections)
{ {

View File

@@ -54,10 +54,10 @@ namespace mRemoteNG.UI.Controls
private readonly IConnectionInitiator _connectionInitiator; private readonly IConnectionInitiator _connectionInitiator;
public ConnectionContextMenu(ConnectionTree connectionTree, IConnectionInitiator connectionInitiator) public ConnectionContextMenu(ConnectionTree connectionTree)
{ {
_connectionTree = connectionTree; _connectionTree = connectionTree;
_connectionInitiator = connectionInitiator; _connectionInitiator = new ConnectionInitiator();
InitializeComponent(); InitializeComponent();
ApplyLanguage(); ApplyLanguage();
EnableShortcutKeys(); EnableShortcutKeys();

View File

@@ -23,8 +23,7 @@ namespace mRemoteNG.UI.Controls
private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler(); private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler();
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance; private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
private readonly StatusImageList _statusImageList = new StatusImageList(); private readonly StatusImageList _statusImageList = new StatusImageList();
private readonly IConnectionInitiator _connectionInitiator; private ThemeManager _themeManager;
private readonly ThemeManager _themeManager;
private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter = private readonly ConnectionTreeSearchTextFilter _connectionTreeSearchTextFilter =
new ConnectionTreeSearchTextFilter(); new ConnectionTreeSearchTextFilter();
@@ -64,7 +63,6 @@ namespace mRemoteNG.UI.Controls
public ConnectionTree() public ConnectionTree()
{ {
_connectionInitiator = Windows.ConnectionInitiator;
InitializeComponent(); InitializeComponent();
SetupConnectionTreeView(); SetupConnectionTreeView();
UseOverlays = false; UseOverlays = false;
@@ -116,7 +114,7 @@ namespace mRemoteNG.UI.Controls
SmallImageList = _statusImageList.ImageList; SmallImageList = _statusImageList.ImageList;
AddColumns(_statusImageList.ImageGetter); AddColumns(_statusImageList.ImageGetter);
LinkModelToView(); LinkModelToView();
_contextMenu = new ConnectionContextMenu(this, _connectionInitiator); _contextMenu = new ConnectionContextMenu(this);
ContextMenuStrip = _contextMenu; ContextMenuStrip = _contextMenu;
SetupDropSink(); SetupDropSink();
SetEventHandlers(); SetEventHandlers();

View File

@@ -22,11 +22,21 @@ namespace mRemoteNG.UI.Controls
private ContextMenuStrip _mnuQuickConnectProtocol; private ContextMenuStrip _mnuQuickConnectProtocol;
private QuickConnectComboBox _cmbQuickConnect; private QuickConnectComboBox _cmbQuickConnect;
private ContextMenuStrip _mnuConnections; private ContextMenuStrip _mnuConnections;
private IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private readonly ThemeManager _themeManager; private readonly ThemeManager _themeManager;
private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender; private WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender vsToolStripExtender;
private readonly DisplayProperties _display; private readonly DisplayProperties _display;
public IConnectionInitiator ConnectionInitiator { get; set; } public IConnectionInitiator ConnectionInitiator
{
get => _connectionInitiator;
set
{
if (value == null)
return;
_connectionInitiator = value;
}
}
public QuickConnectToolStrip() public QuickConnectToolStrip()
{ {

View File

@@ -1,327 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
using mRemoteNG.UI.Tabs;
using Message = System.Windows.Forms.Message;
namespace mRemoteNG.UI.FocusHelpers
{
public class ExternalProcessFocusHelper : IDisposable
{
private readonly IntPtr _mainWindowHandle;
private int _extFocusCount;
private readonly SystemKeyboardHook _keyboardHook;
private bool _currentlyFixingAltTab;
private bool _childProcessHeldLastFocus;
private bool _inSizeMove;
private bool _fixingMainWindowFocus;
/// <summary>
/// TRUE if any part of mrng has focus - the main window or child processes
/// </summary>
public bool MrngFocused => MainWindowFocused || ChildProcessFocused;
/// <summary>
/// TRUE when the main mRemoteNG window has focus.
/// </summary>
public bool MainWindowFocused { get; private set; }
/// <summary>
/// TRUE when a child process (not the mRemoteNG main window) has focus.
/// </summary>
public bool ChildProcessFocused => _extFocusCount > 0;
/// <summary>
/// TRUE when a child process was the last window within mRemoteNG
/// to have focus.
/// </summary>
public bool ChildProcessHeldLastFocus
{
get => _childProcessHeldLastFocus;
private set
{
_childProcessHeldLastFocus = value;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"_childProcessHeldLastFocus={_childProcessHeldLastFocus}");
}
}
public ExternalProcessFocusHelper(
IConnectionInitiator connectionInitiator,
IntPtr mainWindowHandle)
{
connectionInitiator.ConnectionStarting += ConnectionInitiatorOnConnectionStarting;
_mainWindowHandle = mainWindowHandle;
_keyboardHook = new SystemKeyboardHook(KeyboardHookCallback);
}
private void ConnectionInitiatorOnConnectionStarting(object sender, ConnectionStartingEvent e)
{
if (!(e.Protocol is ExternalProcessProtocolBase extProc))
return;
extProc.FocusChanged += ExtProcOnFocusChanged;
extProc.Disconnected += ProtocolOnDisconnected;
}
private void ExtProcOnFocusChanged(object sender, EventArgs e)
{
if (!(sender is IFocusable extProc))
return;
if (extProc.HasFocus)
ExternalWindowFocused();
else
ExternalWindowDefocused();
}
private void ProtocolOnDisconnected(object sender, string disconnectedMessage, int? reasonCode)
{
if (!(sender is ExternalProcessProtocolBase prot))
return;
prot.FocusChanged -= ExtProcOnFocusChanged;
prot.Disconnected -= ProtocolOnDisconnected;
}
public void ActivateConnection()
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Performing special connection focus logic");
//var cw = pnlDock.ActiveDocument as ConnectionWindow;
//var dp = cw?.ActiveControl as DockPane;
//if (!(dp?.ActiveContent is ConnectionTab tab))
//{
// Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Active content is not a tab. We won't focus a specific connection.");
// return;
//}
//var ifc = InterfaceControl.FindInterfaceControl(tab);
var tab = TabHelper.Instance.CurrentTab;
if (tab == null)
return;
var ifc = tab.InterfaceControl;
if (ifc == null)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
$"InterfaceControl for tab '{tab.Name}' was not found. We won't focus that connection.");
return;
}
ifc.Protocol.Focus();
var conFormWindow = ifc.FindForm();
((ConnectionTab)conFormWindow)?.RefreshInterfaceController();
}
/// <summary>
/// Toggle focus between the main window and the last active external app.
/// </summary>
public void ToggleFocus()
{
if (ChildProcessFocused)
{
ForceExtAppToGiveUpFocus();
var focused = NativeMethods.SetForegroundWindow(_mainWindowHandle);
}
else if (MainWindowFocused)
{
ActivateConnection();
}
}
/// <summary>
/// A hook into system keyboard events.
/// </summary>
/// <param name="msg"></param>
/// <param name="kbd"></param>
/// <remarks>
/// This is the only way we can detect ALT-TAB events on Win10, since the EVENT_SYSTEM_SWITCHSTART and
/// EVENT_SYSTEM_SWITCHEND events do not seem to fire. If there is another way to detect that a user
/// is switching between apps using ALT-TAB, then we should try to use that. Hooking into keyboard
/// events like this feels dirty, as it is often used by malicious programs.
/// </remarks>
/// <returns></returns>
private int KeyboardHookCallback(int msg, NativeMethods.KBDLLHOOKSTRUCT kbd)
{
var key = (Keys)kbd.vkCode;
// Alt + Tab
if (key.HasFlag(Keys.Tab) && kbd.flags.HasFlag(NativeMethods.KBDLLHOOKSTRUCTFlags.LLKHF_ALTDOWN))
{
if (msg == NativeMethods.WM_SYSKEYDOWN || msg == NativeMethods.WM_KEYDOWN)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"ALT-TAB PRESSED (CHILDPROC_FOCUSED={ChildProcessFocused}, CHILDPROC_LAST_FOCUSED={ChildProcessHeldLastFocus}, MRNG_FOCUSED={MrngFocused}, CURR_FIXING={_currentlyFixingAltTab})");
if (ChildProcessHeldLastFocus && MrngFocused && !_currentlyFixingAltTab)
{
FixExternalAppAltTab();
}
}
}
return 0;
}
/// <summary>
/// Ensure that focus events on the main window are allowed to complete
/// without the external app stealing focus away.
/// </summary>
private void ForceExtAppToGiveUpFocus()
{
if (!ChildProcessHeldLastFocus)
return;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Forcing extpp to give up focus.");
ChildProcessHeldLastFocus = false;
}
/// <summary>
/// When we alt-tab and an external app has focus,
/// </summary>
private void FixExternalAppAltTab()
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "FIXING ALT-TAB FOR EXTAPP");
_currentlyFixingAltTab = true;
// simulate an extra TAB key press. This skips focus of the mrng main window.
// end the current alt-tab key press
NativeMethods.keybd_event((byte) Keys.Tab, 0, (uint) NativeMethods.KEYEVENTF.KEYUP, 0);
// start a new alt-tab key press
NativeMethods.keybd_event((byte) Keys.Tab, 0, 0, 0);
// WndProc will never get an event when we switch from a child proc to a completely different program since the main mrng window never had focus to begin with.
// Assume mrng as a whole will lose focus, even though the user could choose to retain focus on us. When Alt-tab completes, the mrng main window will
// receive the focus event and we will handle the child process focusing as necessary.
MainWindowFocused = false;
_currentlyFixingAltTab = false;
}
private void ExternalWindowFocused()
{
_extFocusCount++;
ChildProcessHeldLastFocus = true;
}
private void ExternalWindowDefocused()
{
_extFocusCount--;
ChildProcessHeldLastFocus = !MainWindowFocused && !ChildProcessFocused;
}
/// <summary>
/// Give the <see cref="ExternalProcessFocusHelper"/> a chance to
/// hook into a system window's WndProc message handler. Returns
/// true if an action has been taken which should override the
/// base windows own WndProc handling.
/// </summary>
/// <param name="m"></param>
/// <param name="baseWindowProcessMessage">
/// Call this with the current message to allow the default window handler
/// to process the message. Useful if you want to perform some work after
/// the default processing is complete.
/// </param>
/// <returns>
/// Returns true if an action has been taken which should override the
/// base windows own WndProc handling.
/// </returns>
public bool HandleWndProc(ref Message m, Action<Message> baseWindowProcessMessage)
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (m.Msg)
{
case NativeMethods.WM_PARENTNOTIFY:
var notifyType = m.WParam.ToInt32();
// ignore non-click notify events
if (notifyType == NativeMethods.WM_CREATE || notifyType == NativeMethods.WM_DESTROY)
break;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Main window clicked");
// when the main window is clicked, assume the user wants the main window focused
ForceExtAppToGiveUpFocus();
break;
case NativeMethods.WM_ACTIVATEAPP:
if (_fixingMainWindowFocus)
break;
// main window is being deactivated
if (m.WParam.ToInt32() == 0)
{
MainWindowFocused = false;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"mRemoteNG main window lost focus (_childProcessHeldLastFocus={ChildProcessHeldLastFocus})");
break;
}
MainWindowFocused = true;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"mRemoteNG main window received focus (_childProcessHeldLastFocus={ChildProcessHeldLastFocus})");
break;
case NativeMethods.WM_SETFOCUS:
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "WM_SETFOCUS");
_fixingMainWindowFocus = true;
baseWindowProcessMessage(m);
_fixingMainWindowFocus = false;
if (ChildProcessHeldLastFocus && MainWindowFocused)
ActivateConnection();
return true;
case NativeMethods.WM_ACTIVATE:
if (m.WParam.ToInt32() == NativeMethods.WA_INACTIVE)
break;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "WM_ACTIVATE");
break;
case NativeMethods.WM_NCACTIVATE:
// Never allow the mRemoteNG window to display itself as inactive. By doing this,
// we ensure focus events can propagate to child connection windows
NativeMethods.DefWindowProc(_mainWindowHandle, Convert.ToUInt32(m.Msg), (IntPtr)1, m.LParam);
m.Result = (IntPtr)1;
return true;
// handle re-focusing connection when the main window moves or resizes
case NativeMethods.WM_ENTERSIZEMOVE:
_inSizeMove = true;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Begin app window move/resize");
break;
case NativeMethods.WM_EXITSIZEMOVE:
_inSizeMove = false;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "End app window move/resize");
// This handles activations from clicks that started a size/move operation
ActivateConnection();
break;
case NativeMethods.WM_WINDOWPOSCHANGED:
// Ignore this message if the window wasn't activated
if (!MainWindowFocused)
break;
var windowPos = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS));
if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) == 0)
{
if (!MainWindowFocused && !_inSizeMove)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "WM_WINDOWPOSCHANGED DONE");
ActivateConnection();
}
}
break;
}
return false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing)
return;
_keyboardHook?.Dispose();
}
}
}

View File

@@ -1,18 +1,14 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Tools; using mRemoteNG.Tools;
namespace mRemoteNG.UI.Forms.OptionsPages namespace mRemoteNG.UI.Forms.OptionsPages
{ {
public sealed partial class AppearancePage public sealed partial class AppearancePage
{ {
private readonly IConnectionInitiator _connectionInitiator; public AppearancePage()
public AppearancePage(IConnectionInitiator connectionInitiator)
{ {
_connectionInitiator = connectionInitiator;
InitializeComponent(); InitializeComponent();
ApplyTheme(); ApplyTheme();
PageIcon = Resources.Panels_Icon; PageIcon = Resources.Panels_Icon;
@@ -86,7 +82,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages
{ {
if (Runtime.NotificationAreaIcon == null) if (Runtime.NotificationAreaIcon == null)
{ {
Runtime.NotificationAreaIcon = new NotificationAreaIcon(_connectionInitiator); Runtime.NotificationAreaIcon = new NotificationAreaIcon();
} }
} }
else else

View File

@@ -1,6 +1,5 @@
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Themes; using mRemoteNG.Themes;
using mRemoteNG.UI.Forms.Input; using mRemoteNG.UI.Forms.Input;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
@@ -11,10 +10,10 @@ namespace mRemoteNG.UI.Forms
{ {
private readonly PanelAdder _panelAdder; private readonly PanelAdder _panelAdder;
public FrmChoosePanel(IConnectionInitiator connectionInitiator) public FrmChoosePanel()
{ {
InitializeComponent(); InitializeComponent();
_panelAdder = new PanelAdder(connectionInitiator); _panelAdder = new PanelAdder();
} }
public string Panel public string Panel

View File

@@ -31,189 +31,193 @@
[System.Diagnostics.DebuggerStepThrough()] [System.Diagnostics.DebuggerStepThrough()]
private void InitializeComponent() private void InitializeComponent()
{ {
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain)); mRemoteNG.Connection.ConnectionInitiator connectionInitiator1 = new mRemoteNG.Connection.ConnectionInitiator();
this.pnlDock = new WeifenLuo.WinFormsUI.Docking.DockPanel(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain));
this.msMain = new System.Windows.Forms.MenuStrip(); this.pnlDock = new WeifenLuo.WinFormsUI.Docking.DockPanel();
this.fileMenu = new mRemoteNG.UI.Menu.MainFileMenu(); this.msMain = new System.Windows.Forms.MenuStrip();
this.viewMenu = new mRemoteNG.UI.Menu.ViewMenu(); this.fileMenu = new mRemoteNG.UI.Menu.MainFileMenu();
this.toolsMenu = new mRemoteNG.UI.Menu.ToolsMenu(); this.viewMenu = new mRemoteNG.UI.Menu.ViewMenu();
this.helpMenu = new mRemoteNG.UI.Menu.HelpMenu(); this.toolsMenu = new mRemoteNG.UI.Menu.ToolsMenu();
this.mMenSep3 = new System.Windows.Forms.ToolStripSeparator(); this.helpMenu = new mRemoteNG.UI.Menu.HelpMenu();
this.tsContainer = new System.Windows.Forms.ToolStripContainer(); this.mMenSep3 = new System.Windows.Forms.ToolStripSeparator();
this._quickConnectToolStrip = new mRemoteNG.UI.Controls.QuickConnectToolStrip(); this.tsContainer = new System.Windows.Forms.ToolStripContainer();
this._multiSshToolStrip = new mRemoteNG.UI.Controls.MultiSshToolStrip(); this._quickConnectToolStrip = new mRemoteNG.UI.Controls.QuickConnectToolStrip();
this._externalToolsToolStrip = new mRemoteNG.UI.Controls.ExternalToolsToolStrip(); this._multiSshToolStrip = new mRemoteNG.UI.Controls.MultiSshToolStrip();
this.tmrAutoSave = new System.Windows.Forms.Timer(this.components); this._externalToolsToolStrip = new mRemoteNG.UI.Controls.ExternalToolsToolStrip();
this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components); this.tmrAutoSave = new System.Windows.Forms.Timer(this.components);
this.msMain.SuspendLayout(); this.vsToolStripExtender = new WeifenLuo.WinFormsUI.Docking.VisualStudioToolStripExtender(this.components);
this.tsContainer.ContentPanel.SuspendLayout(); this.msMain.SuspendLayout();
this.tsContainer.TopToolStripPanel.SuspendLayout(); this.tsContainer.ContentPanel.SuspendLayout();
this.tsContainer.SuspendLayout(); this.tsContainer.TopToolStripPanel.SuspendLayout();
this.SuspendLayout(); this.tsContainer.SuspendLayout();
// this.SuspendLayout();
// pnlDock //
// // pnlDock
this.pnlDock.Dock = System.Windows.Forms.DockStyle.Fill; //
this.pnlDock.DockBackColor = System.Drawing.SystemColors.Control; this.pnlDock.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlDock.DockLeftPortion = 230D; this.pnlDock.DockBackColor = System.Drawing.SystemColors.Control;
this.pnlDock.DockRightPortion = 230D; this.pnlDock.DockLeftPortion = 230D;
this.pnlDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi; this.pnlDock.DockRightPortion = 230D;
this.pnlDock.Location = new System.Drawing.Point(0, 0); this.pnlDock.DocumentStyle = WeifenLuo.WinFormsUI.Docking.DocumentStyle.DockingSdi;
this.pnlDock.Name = "pnlDock"; this.pnlDock.Location = new System.Drawing.Point(0, 0);
this.pnlDock.Size = new System.Drawing.Size(1129, 471); this.pnlDock.Name = "pnlDock";
this.pnlDock.TabIndex = 13; this.pnlDock.Size = new System.Drawing.Size(1129, 471);
this.pnlDock.ActiveDocumentChanged += new System.EventHandler(this.pnlDock_ActiveDocumentChanged); this.pnlDock.TabIndex = 13;
// this.pnlDock.ActiveDocumentChanged += new System.EventHandler(this.pnlDock_ActiveDocumentChanged);
// msMain //
// // msMain
this.msMain.Anchor = System.Windows.Forms.AnchorStyles.Left; //
this.msMain.Dock = System.Windows.Forms.DockStyle.None; this.msMain.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.msMain.GripMargin = new System.Windows.Forms.Padding(2); this.msMain.Dock = System.Windows.Forms.DockStyle.None;
this.msMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Visible; this.msMain.GripMargin = new System.Windows.Forms.Padding(2);
this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.msMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Visible;
this.msMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileMenu, this.fileMenu,
this.viewMenu, this.viewMenu,
this.toolsMenu, this.toolsMenu,
this.helpMenu}); this.helpMenu});
this.msMain.Location = new System.Drawing.Point(3, 50); this.msMain.Location = new System.Drawing.Point(3, 50);
this.msMain.Name = "msMain"; this.msMain.Name = "msMain";
this.msMain.Padding = new System.Windows.Forms.Padding(0, 0, 1, 0); this.msMain.Padding = new System.Windows.Forms.Padding(0, 0, 1, 0);
this.msMain.Size = new System.Drawing.Size(184, 25); this.msMain.Size = new System.Drawing.Size(184, 25);
this.msMain.Stretch = false; this.msMain.Stretch = false;
this.msMain.TabIndex = 0; this.msMain.TabIndex = 0;
this.msMain.Text = "Main Toolbar"; this.msMain.Text = "Main Toolbar";
// //
// fileMenu // fileMenu
// //
this.fileMenu.ConnectionInitiator = null; this.fileMenu.ConnectionInitiator = null;
this.fileMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.fileMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.fileMenu.Name = "mMenFile"; this.fileMenu.Name = "mMenFile";
this.fileMenu.Size = new System.Drawing.Size(37, 19); this.fileMenu.Size = new System.Drawing.Size(37, 19);
this.fileMenu.Text = "&File"; this.fileMenu.Text = "&File";
this.fileMenu.TreeWindow = null; this.fileMenu.TreeWindow = null;
this.fileMenu.DropDownOpening += new System.EventHandler(this.mainFileMenu1_DropDownOpening); this.fileMenu.DropDownOpening += new System.EventHandler(this.mainFileMenu1_DropDownOpening);
// //
// viewMenu // viewMenu
// //
this.viewMenu.FullscreenHandler = null; this.viewMenu.FullscreenHandler = null;
this.viewMenu.MainForm = null; this.viewMenu.MainForm = null;
this.viewMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.viewMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.viewMenu.Name = "mMenView"; this.viewMenu.Name = "mMenView";
this.viewMenu.Size = new System.Drawing.Size(44, 19); this.viewMenu.Size = new System.Drawing.Size(44, 19);
this.viewMenu.Text = "&View"; this.viewMenu.Text = "&View";
this.viewMenu.TsExternalTools = null; this.viewMenu.TsExternalTools = null;
this.viewMenu.TsMultiSsh = null; this.viewMenu.TsMultiSsh = null;
this.viewMenu.TsQuickConnect = null; this.viewMenu.TsQuickConnect = null;
this.viewMenu.DropDownOpening += new System.EventHandler(this.ViewMenu_Opening); this.viewMenu.DropDownOpening += new System.EventHandler(this.ViewMenu_Opening);
// //
// toolsMenu // toolsMenu
// //
this.toolsMenu.CredentialProviderCatalog = null; this.toolsMenu.CredentialProviderCatalog = null;
this.toolsMenu.MainForm = null; this.toolsMenu.MainForm = null;
this.toolsMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.toolsMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.toolsMenu.Name = "mMenTools"; this.toolsMenu.Name = "mMenTools";
this.toolsMenu.Size = new System.Drawing.Size(47, 19); this.toolsMenu.Size = new System.Drawing.Size(47, 19);
this.toolsMenu.Text = "&Tools"; this.toolsMenu.Text = "&Tools";
// //
// helpMenu // helpMenu
// //
this.helpMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); this.helpMenu.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.helpMenu.Name = "mMenInfo"; this.helpMenu.Name = "mMenInfo";
this.helpMenu.Size = new System.Drawing.Size(44, 19); this.helpMenu.Size = new System.Drawing.Size(44, 19);
this.helpMenu.Text = "&Help"; this.helpMenu.Text = "&Help";
this.helpMenu.TextDirection = System.Windows.Forms.ToolStripTextDirection.Horizontal; this.helpMenu.TextDirection = System.Windows.Forms.ToolStripTextDirection.Horizontal;
// //
// mMenSep3 // mMenSep3
// //
this.mMenSep3.Name = "mMenSep3"; this.mMenSep3.Name = "mMenSep3";
this.mMenSep3.Size = new System.Drawing.Size(211, 6); this.mMenSep3.Size = new System.Drawing.Size(211, 6);
// //
// tsContainer // tsContainer
// //
// //
// tsContainer.ContentPanel // tsContainer.ContentPanel
// //
this.tsContainer.ContentPanel.Controls.Add(this.pnlDock); this.tsContainer.ContentPanel.Controls.Add(this.pnlDock);
this.tsContainer.ContentPanel.Size = new System.Drawing.Size(1129, 471); this.tsContainer.ContentPanel.Size = new System.Drawing.Size(1129, 471);
this.tsContainer.Dock = System.Windows.Forms.DockStyle.Fill; this.tsContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.tsContainer.Location = new System.Drawing.Point(0, 0); this.tsContainer.Location = new System.Drawing.Point(0, 0);
this.tsContainer.Name = "tsContainer"; this.tsContainer.Name = "tsContainer";
this.tsContainer.Size = new System.Drawing.Size(1129, 571); this.tsContainer.Size = new System.Drawing.Size(1129, 571);
this.tsContainer.TabIndex = 17; this.tsContainer.TabIndex = 17;
this.tsContainer.Text = "ToolStripContainer1"; this.tsContainer.Text = "ToolStripContainer1";
// //
// tsContainer.TopToolStripPanel // tsContainer.TopToolStripPanel
// //
this.tsContainer.TopToolStripPanel.Controls.Add(this._quickConnectToolStrip); this.tsContainer.TopToolStripPanel.Controls.Add(this._quickConnectToolStrip);
this.tsContainer.TopToolStripPanel.Controls.Add(this._multiSshToolStrip); this.tsContainer.TopToolStripPanel.Controls.Add(this._multiSshToolStrip);
this.tsContainer.TopToolStripPanel.Controls.Add(this.msMain); this.tsContainer.TopToolStripPanel.Controls.Add(this.msMain);
this.tsContainer.TopToolStripPanel.Controls.Add(this._externalToolsToolStrip); this.tsContainer.TopToolStripPanel.Controls.Add(this._externalToolsToolStrip);
this.tsContainer.TopToolStripPanel.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; this.tsContainer.TopToolStripPanel.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional;
// //
// _quickConnectToolStrip // _quickConnectToolStrip
// //
this._quickConnectToolStrip.BackColor = System.Drawing.SystemColors.Control; this._quickConnectToolStrip.BackColor = System.Drawing.SystemColors.Control;
this._quickConnectToolStrip.Dock = System.Windows.Forms.DockStyle.None; this._quickConnectToolStrip.ConnectionInitiator = connectionInitiator1;
this._quickConnectToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; this._quickConnectToolStrip.Dock = System.Windows.Forms.DockStyle.None;
this._quickConnectToolStrip.Location = new System.Drawing.Point(3, 0); this._quickConnectToolStrip.ForeColor = System.Drawing.SystemColors.ControlText;
this._quickConnectToolStrip.Name = "_quickConnectToolStrip"; this._quickConnectToolStrip.Location = new System.Drawing.Point(3, 0);
this._quickConnectToolStrip.Size = new System.Drawing.Size(364, 25); this._quickConnectToolStrip.Name = "_quickConnectToolStrip";
this._quickConnectToolStrip.TabIndex = 18; this._quickConnectToolStrip.Size = new System.Drawing.Size(364, 25);
// this._quickConnectToolStrip.TabIndex = 18;
// _multiSshToolStrip //
// // _multiSshToolStrip
this._multiSshToolStrip.Dock = System.Windows.Forms.DockStyle.None; //
this._multiSshToolStrip.Location = new System.Drawing.Point(3, 25); this._multiSshToolStrip.Dock = System.Windows.Forms.DockStyle.None;
this._multiSshToolStrip.MinimumSize = new System.Drawing.Size(300, 0); this._multiSshToolStrip.Location = new System.Drawing.Point(3, 25);
this._multiSshToolStrip.Name = "_multiSshToolStrip"; this._multiSshToolStrip.MinimumSize = new System.Drawing.Size(300, 0);
this._multiSshToolStrip.Size = new System.Drawing.Size(376, 25); this._multiSshToolStrip.Name = "_multiSshToolStrip";
this._multiSshToolStrip.TabIndex = 1; this._multiSshToolStrip.Size = new System.Drawing.Size(376, 25);
// this._multiSshToolStrip.TabIndex = 1;
// _externalToolsToolStrip //
// // _externalToolsToolStrip
this._externalToolsToolStrip.BackColor = System.Drawing.SystemColors.Control; //
this._externalToolsToolStrip.Dock = System.Windows.Forms.DockStyle.None; this._externalToolsToolStrip.BackColor = System.Drawing.SystemColors.Control;
this._externalToolsToolStrip.ForeColor = System.Drawing.SystemColors.ControlText; this._externalToolsToolStrip.Dock = System.Windows.Forms.DockStyle.None;
this._externalToolsToolStrip.Location = new System.Drawing.Point(3, 75); this._externalToolsToolStrip.ForeColor = System.Drawing.SystemColors.ControlText;
this._externalToolsToolStrip.Name = "_externalToolsToolStrip"; this._externalToolsToolStrip.Location = new System.Drawing.Point(3, 75);
this._externalToolsToolStrip.Size = new System.Drawing.Size(111, 25); this._externalToolsToolStrip.Name = "_externalToolsToolStrip";
this._externalToolsToolStrip.TabIndex = 17; this._externalToolsToolStrip.Size = new System.Drawing.Size(111, 25);
// this._externalToolsToolStrip.TabIndex = 17;
// tmrAutoSave //
// // tmrAutoSave
this.tmrAutoSave.Interval = 10000; //
this.tmrAutoSave.Tick += new System.EventHandler(this.tmrAutoSave_Tick); this.tmrAutoSave.Interval = 10000;
// this.tmrAutoSave.Tick += new System.EventHandler(this.tmrAutoSave_Tick);
// vsToolStripExtender //
// // vsToolStripExtender
this.vsToolStripExtender.DefaultRenderer = null; //
// this.vsToolStripExtender.DefaultRenderer = null;
// FrmMain //
// // FrmMain
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.ClientSize = new System.Drawing.Size(1129, 571); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.Controls.Add(this.tsContainer); this.ClientSize = new System.Drawing.Size(1129, 571);
this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Controls.Add(this.tsContainer);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.MainMenuStrip = this.msMain; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(400, 400); this.MainMenuStrip = this.msMain;
this.Name = "FrmMain"; this.MinimumSize = new System.Drawing.Size(400, 400);
this.Opacity = 0D; this.Name = "FrmMain";
this.Text = " "; this.Opacity = 0D;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing); this.Text = " ";
this.Load += new System.EventHandler(this.frmMain_Load); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing);
this.Shown += new System.EventHandler(this.frmMain_Shown); this.Load += new System.EventHandler(this.frmMain_Load);
this.Resize += new System.EventHandler(this.frmMain_Resize); this.Shown += new System.EventHandler(this.frmMain_Shown);
this.msMain.ResumeLayout(false); this.ResizeBegin += new System.EventHandler(this.frmMain_ResizeBegin);
this.msMain.PerformLayout(); this.ResizeEnd += new System.EventHandler(this.frmMain_ResizeEnd);
this.tsContainer.ContentPanel.ResumeLayout(false); this.Resize += new System.EventHandler(this.frmMain_Resize);
this.tsContainer.TopToolStripPanel.ResumeLayout(false); this.msMain.ResumeLayout(false);
this.tsContainer.TopToolStripPanel.PerformLayout(); this.msMain.PerformLayout();
this.tsContainer.ResumeLayout(false); this.tsContainer.ContentPanel.ResumeLayout(false);
this.tsContainer.PerformLayout(); this.tsContainer.TopToolStripPanel.ResumeLayout(false);
this.ResumeLayout(false); this.tsContainer.TopToolStripPanel.PerformLayout();
this.tsContainer.ResumeLayout(false);
this.tsContainer.PerformLayout();
this.ResumeLayout(false);
} }
internal WeifenLuo.WinFormsUI.Docking.DockPanel pnlDock; internal WeifenLuo.WinFormsUI.Docking.DockPanel pnlDock;

View File

@@ -8,14 +8,11 @@ using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Putty; using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Settings; using mRemoteNG.Config.Settings;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages; using mRemoteNG.Messages;
using mRemoteNG.Messages.MessageWriters; using mRemoteNG.Messages.MessageWriters;
using mRemoteNG.Themes; using mRemoteNG.Themes;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using mRemoteNG.UI.FocusHelpers;
using mRemoteNG.UI.Menu; using mRemoteNG.UI.Menu;
using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Tabs; using mRemoteNG.UI.Tabs;
using mRemoteNG.UI.TaskDialog; using mRemoteNG.UI.TaskDialog;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -26,10 +23,11 @@ using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.UI.Panels;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
using Message = System.Windows.Forms.Message;
// ReSharper disable MemberCanBePrivate.Global // ReSharper disable MemberCanBePrivate.Global
@@ -40,6 +38,8 @@ namespace mRemoteNG.UI.Forms
public static FrmMain Default { get; } = new FrmMain(); public static FrmMain Default { get; } = new FrmMain();
private static ClipboardchangeEventHandler _clipboardChangedEvent; private static ClipboardchangeEventHandler _clipboardChangedEvent;
private bool _inSizeMove;
private bool _inMouseActivate;
private IntPtr _fpChainedWindowHandle; private IntPtr _fpChainedWindowHandle;
private bool _usingSqlServer; private bool _usingSqlServer;
private string _connectionsFileName; private string _connectionsFileName;
@@ -49,8 +49,6 @@ namespace mRemoteNG.UI.Forms
private readonly IList<IMessageWriter> _messageWriters = new List<IMessageWriter>(); private readonly IList<IMessageWriter> _messageWriters = new List<IMessageWriter>();
private readonly ThemeManager _themeManager; private readonly ThemeManager _themeManager;
private readonly FileBackupPruner _backupPruner = new FileBackupPruner(); private readonly FileBackupPruner _backupPruner = new FileBackupPruner();
private readonly IConnectionInitiator _connectionInitiator;
private readonly ExternalProcessFocusHelper _focusHelper;
internal FullscreenHandler Fullscreen { get; set; } internal FullscreenHandler Fullscreen { get; set; }
@@ -69,11 +67,6 @@ namespace mRemoteNG.UI.Forms
ApplyTheme(); ApplyTheme();
_screenSystemMenu = new ScreenSelectionSystemMenu(this); _screenSystemMenu = new ScreenSelectionSystemMenu(this);
var protocolFactory = new ProtocolFactory();
_connectionInitiator = new ConnectionInitiator(protocolFactory);
Debug.Assert(IsHandleCreated, "Expected main window handle to be created by now");
_focusHelper = new ExternalProcessFocusHelper(_connectionInitiator, Handle);
} }
#region Properties #region Properties
@@ -152,11 +145,10 @@ namespace mRemoteNG.UI.Forms
MessageCollectorSetup.SetupMessageCollector(messageCollector, _messageWriters); MessageCollectorSetup.SetupMessageCollector(messageCollector, _messageWriters);
MessageCollectorSetup.BuildMessageWritersFromSettings(_messageWriters); MessageCollectorSetup.BuildMessageWritersFromSettings(_messageWriters);
Windows.ConnectionInitiator = _connectionInitiator;
Startup.Instance.InitializeProgram(messageCollector); Startup.Instance.InitializeProgram(messageCollector);
msMain.Location = Point.Empty; msMain.Location = Point.Empty;
var settingsLoader = new SettingsLoader(this, _connectionInitiator, messageCollector, _quickConnectToolStrip, var settingsLoader = new SettingsLoader(this, messageCollector, _quickConnectToolStrip,
_externalToolsToolStrip, _multiSshToolStrip, msMain); _externalToolsToolStrip, _multiSshToolStrip, msMain);
settingsLoader.LoadSettings(); settingsLoader.LoadSettings();
@@ -208,29 +200,14 @@ namespace mRemoteNG.UI.Forms
ShowInTaskbar = false; ShowInTaskbar = false;
} }
if (Settings.Default.CreateEmptyPanelOnStartUp) if (!Settings.Default.CreateEmptyPanelOnStartUp) return;
{ var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName)
var panelName = !string.IsNullOrEmpty(Settings.Default.StartUpPanelName) ? Settings.Default.StartUpPanelName
? Settings.Default.StartUpPanelName : Language.strNewPanel;
: Language.strNewPanel;
var panelAdder = new PanelAdder(_connectionInitiator); var panelAdder = new PanelAdder();
if (!panelAdder.DoesPanelExist(panelName)) if (!panelAdder.DoesPanelExist(panelName))
panelAdder.AddPanel(panelName); panelAdder.AddPanel(panelName);
}
TabHelper.Instance.ActiveConnectionTabChanged += OnActiveConnectionTabChanged;
TabHelper.Instance.TabClicked += OnTabClicked;
}
private void OnTabClicked(object sender, EventArgs e)
{
_focusHelper.ActivateConnection();
}
private void OnActiveConnectionTabChanged(object sender, EventArgs e)
{
_focusHelper.ActivateConnection();
} }
private void ApplyLanguage() private void ApplyLanguage()
@@ -279,20 +256,20 @@ namespace mRemoteNG.UI.Forms
private void SetMenuDependencies() private void SetMenuDependencies()
{ {
var connectionInitiator = new ConnectionInitiator();
fileMenu.TreeWindow = Windows.TreeForm; fileMenu.TreeWindow = Windows.TreeForm;
fileMenu.ConnectionInitiator = _connectionInitiator; fileMenu.ConnectionInitiator = connectionInitiator;
viewMenu.TsExternalTools = _externalToolsToolStrip; viewMenu.TsExternalTools = _externalToolsToolStrip;
viewMenu.TsQuickConnect = _quickConnectToolStrip; viewMenu.TsQuickConnect = _quickConnectToolStrip;
viewMenu.TsMultiSsh = _multiSshToolStrip; viewMenu.TsMultiSsh = _multiSshToolStrip;
viewMenu.FullscreenHandler = Fullscreen; viewMenu.FullscreenHandler = Fullscreen;
viewMenu.MainForm = this; viewMenu.MainForm = this;
viewMenu.ConnectionInitiator = _connectionInitiator;
toolsMenu.MainForm = this; toolsMenu.MainForm = this;
toolsMenu.CredentialProviderCatalog = Runtime.CredentialProviderCatalog; toolsMenu.CredentialProviderCatalog = Runtime.CredentialProviderCatalog;
_quickConnectToolStrip.ConnectionInitiator = _connectionInitiator; _quickConnectToolStrip.ConnectionInitiator = connectionInitiator;
} }
//Theming support //Theming support
@@ -368,7 +345,7 @@ namespace mRemoteNG.UI.Forms
if (CTaskDialog.CommandButtonResult != 1) return; if (CTaskDialog.CommandButtonResult != 1) return;
using (var optionsForm = new FrmOptions(Language.strTabUpdates, _connectionInitiator)) using (var optionsForm = new FrmOptions(Language.strTabUpdates))
{ {
optionsForm.ShowDialog(this); optionsForm.ShowDialog(this);
} }
@@ -378,8 +355,13 @@ namespace mRemoteNG.UI.Forms
{ {
if (!Settings.Default.CheckForUpdatesOnStartup) return; if (!Settings.Default.CheckForUpdatesOnStartup) return;
var updateFrequencyInDays = Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays); var nextUpdateCheck = Convert.ToDateTime(
var nextUpdateCheck = Settings.Default.CheckForUpdatesLastCheck.AddDays(updateFrequencyInDays); Settings.Default.CheckForUpdatesLastCheck.Add(
TimeSpan
.FromDays(Convert
.ToDouble(Settings
.Default
.CheckForUpdatesFrequencyDays))));
if (!Settings.Default.UpdatePending && DateTime.UtcNow <= nextUpdateCheck) return; if (!Settings.Default.UpdatePending && DateTime.UtcNow <= nextUpdateCheck) return;
if (!IsHandleCreated) if (!IsHandleCreated)
@@ -390,8 +372,6 @@ namespace mRemoteNG.UI.Forms
private void frmMain_FormClosing(object sender, FormClosingEventArgs e) private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{ {
_focusHelper?.Dispose();
if (!(Runtime.WindowList == null || Runtime.WindowList.Count == 0)) if (!(Runtime.WindowList == null || Runtime.WindowList.Count == 0))
{ {
var openConnections = 0; var openConnections = 0;
@@ -460,6 +440,12 @@ namespace mRemoteNG.UI.Forms
#endregion #endregion
#region Window Overrides and DockPanel Stuff #region Window Overrides and DockPanel Stuff
private void frmMain_ResizeBegin(object sender, EventArgs e)
{
_inSizeMove = true;
}
private void frmMain_Resize(object sender, EventArgs e) private void frmMain_Resize(object sender, EventArgs e)
{ {
if (WindowState == FormWindowState.Minimized) if (WindowState == FormWindowState.Minimized)
@@ -467,7 +453,7 @@ namespace mRemoteNG.UI.Forms
if (!Settings.Default.MinimizeToTray) return; if (!Settings.Default.MinimizeToTray) return;
if (Runtime.NotificationAreaIcon == null) if (Runtime.NotificationAreaIcon == null)
{ {
Runtime.NotificationAreaIcon = new NotificationAreaIcon(_connectionInitiator); Runtime.NotificationAreaIcon = new NotificationAreaIcon();
} }
Hide(); Hide();
@@ -478,62 +464,81 @@ namespace mRemoteNG.UI.Forms
} }
} }
// Maybe after starting putty, remove its ability to show up in alt-tab? private void frmMain_ResizeEnd(object sender, EventArgs e)
// SetWindowLong(this.Handle, GWL_EXSTYLE, (GetWindowLong(this.Handle,GWL_EXSTYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW); {
protected override void WndProc(ref Message m) _inSizeMove = false;
// This handles activations from clicks that started a size/move operation
ActivateConnection();
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{ {
// Listen for and handle operating system messages // Listen for and handle operating system messages
try try
{ {
if (_focusHelper?.HandleWndProc(ref m, wm => base.WndProc(ref wm)) == true)
return;
// ReSharper disable once SwitchStatementMissingSomeCases // ReSharper disable once SwitchStatementMissingSomeCases
switch (m.Msg) switch (m.Msg)
{ {
case NativeMethods.WM_MOUSEACTIVATE: case NativeMethods.WM_MOUSEACTIVATE:
var controlThatWasClicked2 = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)) _inMouseActivate = true;
?? GetChildAtPoint(MousePosition); break;
case NativeMethods.WM_ACTIVATEAPP:
var candidateTabToFocus = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition))
?? GetChildAtPoint(MousePosition);
if (controlThatWasClicked2 == null) if (candidateTabToFocus is InterfaceControl)
break; {
candidateTabToFocus.Parent.Focus();
}
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Clicked control: {controlThatWasClicked2}"); _inMouseActivate = false;
break; break;
case NativeMethods.WM_ACTIVATE: case NativeMethods.WM_ACTIVATE:
// Only handle this msg if it was triggered by a click // Only handle this msg if it was triggered by a click
if (NativeMethods.LOWORD(m.WParam) != NativeMethods.WA_CLICKACTIVE) if (NativeMethods.LOWORD(m.WParam) == NativeMethods.WA_CLICKACTIVE)
return; {
var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition))
?? GetChildAtPoint(MousePosition);
if (controlThatWasClicked != null)
{
if (controlThatWasClicked is TreeView ||
controlThatWasClicked is ComboBox ||
controlThatWasClicked is TextBox ||
controlThatWasClicked is FrmMain)
{
controlThatWasClicked.Focus();
}
else if (controlThatWasClicked.CanSelect ||
controlThatWasClicked is MenuStrip ||
controlThatWasClicked is ToolStrip)
{
// Simulate a mouse event since one wasn't generated by Windows
SimulateClick(controlThatWasClicked);
controlThatWasClicked.Focus();
}
else if (controlThatWasClicked is AutoHideStripBase)
{
// only focus the autohide toolstrip
controlThatWasClicked.Focus();
}
else
{
// This handles activations from clicks that did not start a size/move operation
ActivateConnection();
}
}
}
var controlThatWasClicked = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition)) break;
?? GetChildAtPoint(MousePosition); case NativeMethods.WM_WINDOWPOSCHANGED:
// Ignore this message if the window wasn't activated
if (controlThatWasClicked == null) var windowPos =
break; (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS));
if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) == 0)
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Click activate: {controlThatWasClicked}"); {
if (!_inMouseActivate && !_inSizeMove)
//if (controlThatWasClicked is TreeView || ActivateConnection();
// controlThatWasClicked is ComboBox || }
// controlThatWasClicked is TextBox ||
// controlThatWasClicked is FrmMain ||
// controlThatWasClicked is AutoHideStripBase)
//{
// controlThatWasClicked.Focus();
//}
//else if (controlThatWasClicked.CanSelect ||
// controlThatWasClicked is MenuStrip ||
// controlThatWasClicked is ToolStrip)
//{
// // Simulate a mouse event since one wasn't generated by Windows
// SimulateClick(controlThatWasClicked);
// controlThatWasClicked.Focus();
//}
//else
//{
// // This handles activations from clicks that did not start a size/move operation
// ActivateConnection();
//}
break; break;
case NativeMethods.WM_SYSCOMMAND: case NativeMethods.WM_SYSCOMMAND:
@@ -571,9 +576,23 @@ namespace mRemoteNG.UI.Forms
clientMousePosition.Y = temp_wHigh; clientMousePosition.Y = temp_wHigh;
} }
private void ActivateConnection()
{
var cw = pnlDock.ActiveDocument as ConnectionWindow;
var dp = cw?.ActiveControl as DockPane;
if (!(dp?.ActiveContent is ConnectionTab tab)) return;
var ifc = InterfaceControl.FindInterfaceControl(tab);
if (ifc == null) return;
ifc.Protocol.Focus();
var conFormWindow = ifc.FindForm();
((ConnectionTab)conFormWindow)?.RefreshInterfaceController();
}
private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e) private void pnlDock_ActiveDocumentChanged(object sender, EventArgs e)
{ {
//_focusHelper.ActivateConnection(); ActivateConnection();
} }
internal void UpdateWindowTitle() internal void UpdateWindowTitle()

View File

@@ -4,30 +4,26 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.Connection;
using mRemoteNG.Themes; using mRemoteNG.Themes;
namespace mRemoteNG.UI.Forms namespace mRemoteNG.UI.Forms
{ {
public partial class FrmOptions : Form public partial class FrmOptions : Form
{ {
private readonly IConnectionInitiator _connectionInitiator;
private Dictionary<string, OptionsPage> _pages; private Dictionary<string, OptionsPage> _pages;
private readonly string _pageName; private readonly string _pageName;
private readonly DisplayProperties _display = new DisplayProperties(); private readonly DisplayProperties _display = new DisplayProperties();
public FrmOptions(IConnectionInitiator connectionInitiator) public FrmOptions() : this(Language.strStartupExit)
: this(Language.strStartupExit, connectionInitiator)
{ {
} }
public FrmOptions(string pn, IConnectionInitiator connectionInitiator) public FrmOptions(string pn)
{ {
Cursor.Current = Cursors.WaitCursor; Cursor.Current = Cursors.WaitCursor;
Application.DoEvents(); Application.DoEvents();
InitializeComponent(); InitializeComponent();
_pageName = pn; _pageName = pn;
_connectionInitiator = connectionInitiator;
Cursor.Current = Cursors.Default; Cursor.Current = Cursors.Default;
} }
@@ -72,7 +68,7 @@ namespace mRemoteNG.UI.Forms
_pages = new Dictionary<string, OptionsPage> _pages = new Dictionary<string, OptionsPage>
{ {
{typeof(StartupExitPage).Name, new StartupExitPage {Dock = DockStyle.Fill}}, {typeof(StartupExitPage).Name, new StartupExitPage {Dock = DockStyle.Fill}},
{typeof(AppearancePage).Name, new AppearancePage(_connectionInitiator) {Dock = DockStyle.Fill}}, {typeof(AppearancePage).Name, new AppearancePage {Dock = DockStyle.Fill}},
{typeof(TabsPanelsPage).Name, new TabsPanelsPage {Dock = DockStyle.Fill}}, {typeof(TabsPanelsPage).Name, new TabsPanelsPage {Dock = DockStyle.Fill}},
{typeof(NotificationsPage).Name, new NotificationsPage {Dock = DockStyle.Fill}}, {typeof(NotificationsPage).Name, new NotificationsPage {Dock = DockStyle.Fill}},
{typeof(ConnectionsPage).Name, new ConnectionsPage {Dock = DockStyle.Fill}}, {typeof(ConnectionsPage).Name, new ConnectionsPage {Dock = DockStyle.Fill}},

View File

@@ -453,7 +453,7 @@ namespace mRemoteNG.UI.Menu
if (!(window is ConnectionWindow connectionWindow)) if (!(window is ConnectionWindow connectionWindow))
return; return;
connectionWindow.ReconnectAll(ConnectionInitiator); connectionWindow.reconnectAll(ConnectionInitiator);
} }
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels; using mRemoteNG.UI.Panels;
using mRemoteNG.UI.Window; using mRemoteNG.UI.Window;
@@ -28,6 +27,7 @@ namespace mRemoteNG.UI.Menu
private ToolStripMenuItem _mMenViewResetLayout; private ToolStripMenuItem _mMenViewResetLayout;
private ToolStripMenuItem _mMenViewLockToolbars; private ToolStripMenuItem _mMenViewLockToolbars;
private ToolStripSeparator _toolStripSeparator1; private ToolStripSeparator _toolStripSeparator1;
private readonly PanelAdder _panelAdder;
public ToolStrip TsExternalTools { get; set; } public ToolStrip TsExternalTools { get; set; }
@@ -35,12 +35,12 @@ namespace mRemoteNG.UI.Menu
public ToolStrip TsMultiSsh { get; set; } public ToolStrip TsMultiSsh { get; set; }
public FullscreenHandler FullscreenHandler { get; set; } public FullscreenHandler FullscreenHandler { get; set; }
public FrmMain MainForm { get; set; } public FrmMain MainForm { get; set; }
public IConnectionInitiator ConnectionInitiator { get; set; }
public ViewMenu() public ViewMenu()
{ {
Initialize(); Initialize();
_panelAdder = new PanelAdder();
} }
private void Initialize() private void Initialize()
@@ -374,7 +374,7 @@ namespace mRemoteNG.UI.Menu
private void mMenViewAddConnectionPanel_Click(object sender, EventArgs e) private void mMenViewAddConnectionPanel_Click(object sender, EventArgs e)
{ {
new PanelAdder(ConnectionInitiator).AddPanel(); _panelAdder.AddPanel();
} }
private void mMenViewExtAppsToolbar_Click(object sender, EventArgs e) private void mMenViewExtAppsToolbar_Click(object sender, EventArgs e)

View File

@@ -7,25 +7,17 @@ using System;
using System.Collections; using System.Collections;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.Connection;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNG.UI.Panels namespace mRemoteNG.UI.Panels
{ {
public class PanelAdder public class PanelAdder
{ {
private readonly IConnectionInitiator _connectionInitiator;
public PanelAdder(IConnectionInitiator connectionInitiator)
{
_connectionInitiator = connectionInitiator;
}
public ConnectionWindow AddPanel(string title = "") public ConnectionWindow AddPanel(string title = "")
{ {
try try
{ {
var connectionForm = new ConnectionWindow(new DockContent(), _connectionInitiator); var connectionForm = new ConnectionWindow(new DockContent());
BuildConnectionWindowContextMenu(connectionForm); BuildConnectionWindowContextMenu(connectionForm);
SetConnectionWindowTitle(title, connectionForm); SetConnectionWindowTitle(title, connectionForm);
ShowConnectionWindow(connectionForm); ShowConnectionWindow(connectionForm);

View File

@@ -1,60 +0,0 @@
using mRemoteNG.App;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace mRemoteNG.UI
{
public class SystemKeyboardHook : IDisposable
{
private readonly IntPtr _hookId;
private readonly Func<int, NativeMethods.KBDLLHOOKSTRUCT, int> _userCallback;
private readonly NativeMethods.LowLevelKeyboardProc _sysCallback;
private bool _disposed;
public SystemKeyboardHook(Func<int, NativeMethods.KBDLLHOOKSTRUCT, int> proc)
{
_userCallback = proc;
_sysCallback = SystemCallback;
using (var curProcess = Process.GetCurrentProcess())
using (var curModule = curProcess.MainModule)
{
_hookId = NativeMethods.SetWindowsHookEx(
NativeMethods.WH_KEYBOARD_LL,
_sysCallback,
NativeMethods.GetModuleHandle(curModule.ModuleName),
0);
}
}
private IntPtr SystemCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var kdb = Marshal.PtrToStructure<NativeMethods.KBDLLHOOKSTRUCT>(lParam);
return new IntPtr(_userCallback(wParam.ToInt32(), kdb));
}
return NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
NativeMethods.UnhookWindowsHookEx(_hookId);
}
_disposed = true;
}
}
}

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Diagnostics;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.App.Info; using mRemoteNG.App.Info;
@@ -7,7 +6,6 @@ using mRemoteNG.Config;
using mRemoteNG.Connection; using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol; using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Messages;
using mRemoteNG.UI.TaskDialog; using mRemoteNG.UI.TaskDialog;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
@@ -15,73 +13,81 @@ namespace mRemoteNG.UI.Tabs
{ {
public partial class ConnectionTab : DockContent public partial class ConnectionTab : DockContent
{ {
public InterfaceControl InterfaceControl => Tag as InterfaceControl;
/// <summary> /// <summary>
///Silent close ignores the popup asking for confirmation ///Silent close ignores the popup asking for confirmation
/// </summary> /// </summary>
public bool SilentClose { get; set; } public bool silentClose { get; set; }
/// <summary> /// <summary>
/// Protocol close ignores the interface controller cleanup and the user confirmation dialog /// Protocol close ignores the interface controller cleanup and the user confirmation dialog
/// </summary> /// </summary>
public bool ProtocolClose { get; set; } public bool protocolClose { get; set; }
public ConnectionTab() public ConnectionTab()
{ {
InitializeComponent(); InitializeComponent();
GotFocus += ConnectionTab_GotFocus; GotFocus += ConnectionTab_GotFocus;
Activated += OnActivated;
Click += OnClick;
}
private void OnClick(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab clicked: '{TabText}'");
}
private void OnActivated(object sender, EventArgs e)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab activated: '{TabText}'");
} }
private void ConnectionTab_GotFocus(object sender, EventArgs e) private void ConnectionTab_GotFocus(object sender, EventArgs e)
{ {
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab received focused: '{TabText}'");
TabHelper.Instance.CurrentTab = this; TabHelper.Instance.CurrentTab = this;
} }
protected override void OnFormClosing(FormClosingEventArgs e) protected override void OnFormClosing(FormClosingEventArgs e)
{ {
if (!ProtocolClose) if (!protocolClose)
{ {
if (!SilentClose) if (!silentClose)
{ {
if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All) if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All)
{ {
ShowCloseConnectionTabPrompt(e); var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName,
string
.Format(Language.strConfirmCloseConnectionPanelMainInstruction,
TabText), "", "", "",
Language.strCheckboxDoNotShowThisMessageAgain,
ETaskDialogButtons.YesNo, ESysIcons.Question,
ESysIcons.Question);
if (CTaskDialog.VerificationChecked)
{
Settings.Default.ConfirmCloseConnection--;
}
if (result == DialogResult.No)
{
e.Cancel = true;
}
else
{
((InterfaceControl)Tag)?.Protocol.Close();
}
} }
else else
{ {
// close without the confirmation prompt... // close without the confirmation prompt...
InterfaceControl?.Protocol.Close(); ((InterfaceControl)Tag)?.Protocol.Close();
} }
} }
else else
{ {
InterfaceControl?.Protocol.Close(); ((InterfaceControl)Tag)?.Protocol.Close();
} }
} }
base.OnFormClosing(e); base.OnFormClosing(e);
} }
#region HelperFunctions
public void RefreshInterfaceController() public void RefreshInterfaceController()
{ {
try try
{ {
if (InterfaceControl?.Info.Protocol == ProtocolType.VNC) var interfaceControl = Tag as InterfaceControl;
((ProtocolVNC)InterfaceControl.Protocol).RefreshScreen(); if (interfaceControl?.Info.Protocol == ProtocolType.VNC)
((ProtocolVNC)interfaceControl.Protocol).RefreshScreen();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -89,28 +95,6 @@ namespace mRemoteNG.UI.Tabs
} }
} }
private void ShowCloseConnectionTabPrompt(FormClosingEventArgs e) #endregion
{
var result = CTaskDialog.MessageBox(this, GeneralAppInfo.ProductName,
string.Format(Language.strConfirmCloseConnectionPanelMainInstruction, TabText),
"", "", "",
Language.strCheckboxDoNotShowThisMessageAgain,
ETaskDialogButtons.YesNo, ESysIcons.Question,
ESysIcons.Question);
if (CTaskDialog.VerificationChecked)
{
Settings.Default.ConfirmCloseConnection--;
}
if (result == DialogResult.No)
{
e.Cancel = true;
}
else
{
InterfaceControl?.Protocol.Close();
}
}
} }
} }

View File

@@ -1088,22 +1088,11 @@ namespace mRemoteNG.UI.Tabs
protected override void OnMouseDown(MouseEventArgs e) protected override void OnMouseDown(MouseEventArgs e)
{ {
App.Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Mouse down");
base.OnMouseDown(e); base.OnMouseDown(e);
// suspend drag if mouse is down on active close button. // suspend drag if mouse is down on active close button.
m_suspendDrag = ActiveCloseHitTest(e.Location); m_suspendDrag = ActiveCloseHitTest(e.Location);
if (!IsMouseDown) if (!IsMouseDown)
IsMouseDown = true; IsMouseDown = true;
var tabIndex = HitTest(e.Location);
if (tabIndex < 0 || tabIndex >= Tabs.Count)
return;
var tab = Tabs[tabIndex].Content as ConnectionTab;
if (tab == null)
return;
TabHelper.Instance.CurrentTab = tab;
TabHelper.Instance.RaiseTabClickedEvent();
} }
protected override void OnMouseMove(MouseEventArgs e) protected override void OnMouseMove(MouseEventArgs e)
@@ -1160,7 +1149,6 @@ namespace mRemoteNG.UI.Tabs
protected override void OnMouseClick(MouseEventArgs e) protected override void OnMouseClick(MouseEventArgs e)
{ {
App.Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Mouse click");
base.OnMouseClick(e); base.OnMouseClick(e);
if (e.Button != MouseButtons.Left || Appearance != DockPane.AppearanceStyle.Document) if (e.Button != MouseButtons.Left || Appearance != DockPane.AppearanceStyle.Document)
return; return;

View File

@@ -4,18 +4,12 @@ using System;
namespace mRemoteNG.UI.Tabs namespace mRemoteNG.UI.Tabs
{ {
public class TabHelper class TabHelper
{ {
private static readonly Lazy<TabHelper> lazyHelper = new Lazy<TabHelper>(() => new TabHelper()); private static readonly Lazy<TabHelper> lazyHelper = new Lazy<TabHelper>(() => new TabHelper());
public static TabHelper Instance => lazyHelper.Value; public static TabHelper Instance => lazyHelper.Value;
/// <summary>
/// Should focus events on a connection tab automatically focus
/// its child connection?
/// </summary>
public bool FocusConnection { get; set; } = true;
private TabHelper() private TabHelper()
{ {
} }
@@ -27,16 +21,10 @@ namespace mRemoteNG.UI.Tabs
get => currentTab; get => currentTab;
set set
{ {
if (currentTab == value)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Tab already current: '{currentTab.TabText}'");
return;
}
currentTab = value; currentTab = value;
findCurrentPanel(); findCurrentPanel();
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Current tab changed: '{currentTab.TabText}'"); Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg,
RaiseActiveConnectionTabChangedEvent(); "Tab got focused: " + currentTab.TabText);
} }
} }
@@ -48,7 +36,7 @@ namespace mRemoteNG.UI.Tabs
currentForm = currentForm.Parent; currentForm = currentForm.Parent;
} }
if (currentForm != null && CurrentPanel != currentForm) if (currentForm != null)
CurrentPanel = (ConnectionWindow)currentForm; CurrentPanel = (ConnectionWindow)currentForm;
} }
@@ -59,31 +47,10 @@ namespace mRemoteNG.UI.Tabs
get => currentPanel; get => currentPanel;
set set
{ {
if (currentPanel == value)
return;
currentPanel = value; currentPanel = value;
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Current panel changed: '{currentPanel.TabText}'"); Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg,
RaiseActivePanelChangedEvent(); "Panel got focused: " + currentPanel.TabText);
} }
} }
public event EventHandler ActivePanelChanged;
protected virtual void RaiseActivePanelChangedEvent()
{
ActivePanelChanged?.Invoke(this, EventArgs.Empty);
}
public event EventHandler ActiveConnectionTabChanged;
protected virtual void RaiseActiveConnectionTabChangedEvent()
{
ActiveConnectionTabChanged?.Invoke(this, EventArgs.Empty);
}
public event EventHandler TabClicked;
public void RaiseTabClickedEvent()
{
TabClicked?.Invoke(this, EventArgs.Empty);
}
} }
} }

View File

@@ -21,7 +21,7 @@ namespace mRemoteNG.UI.Window
{ {
public partial class ConnectionTreeWindow public partial class ConnectionTreeWindow
{ {
private readonly IConnectionInitiator _connectionInitiator; private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private ThemeManager _themeManager; private ThemeManager _themeManager;
private bool sortedAz = true; private bool sortedAz = true;
@@ -33,14 +33,12 @@ namespace mRemoteNG.UI.Window
set { olvConnections = value; } set { olvConnections = value; }
} }
public ConnectionTreeWindow(IConnectionInitiator connectionInitiator) public ConnectionTreeWindow() : this(new DockContent())
: this(new DockContent(), connectionInitiator)
{ {
} }
public ConnectionTreeWindow(DockContent panel, IConnectionInitiator connectionInitiator) public ConnectionTreeWindow(DockContent panel)
{ {
_connectionInitiator = connectionInitiator;
WindowType = WindowType.Tree; WindowType = WindowType.Tree;
DockPnl = panel; DockPnl = panel;
InitializeComponent(); InitializeComponent();

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using mRemoteNG.App; using mRemoteNG.App;
@@ -24,15 +23,14 @@ namespace mRemoteNG.UI.Window
{ {
public partial class ConnectionWindow : BaseWindow public partial class ConnectionWindow : BaseWindow
{ {
private readonly IConnectionInitiator _connectionInitiator; private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private VisualStudioToolStripExtender vsToolStripExtender; private VisualStudioToolStripExtender vsToolStripExtender;
private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer(); private readonly ToolStripRenderer _toolStripProfessionalRenderer = new ToolStripProfessionalRenderer();
#region Public Methods #region Public Methods
public ConnectionWindow(DockContent panel, IConnectionInitiator connectionInitiator, string formText = "") public ConnectionWindow(DockContent panel, string formText = "")
{ {
_connectionInitiator = connectionInitiator;
if (formText == "") if (formText == "")
{ {
formText = Language.strNewPanel; formText = Language.strNewPanel;
@@ -98,7 +96,6 @@ namespace mRemoteNG.UI.Window
private void ConnectionWindow_GotFocus(object sender, EventArgs e) private void ConnectionWindow_GotFocus(object sender, EventArgs e)
{ {
TabHelper.Instance.CurrentPanel = this; TabHelper.Instance.CurrentPanel = this;
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Connection window focused: '{TabText}'");
} }
public ConnectionTab AddConnectionTab(ConnectionInfo connectionInfo) public ConnectionTab AddConnectionTab(ConnectionInfo connectionInfo)
@@ -134,7 +131,7 @@ namespace mRemoteNG.UI.Window
var conTab = new ConnectionTab var conTab = new ConnectionTab
{ {
Tag = connectionInfo, // BUG: the Tag gets set to an InterfaceControl later on. Is this right? Tag = connectionInfo,
DockAreas = DockAreas.Document | DockAreas.Float, DockAreas = DockAreas.Document | DockAreas.Float,
Icon = ConnectionIcon.FromString(connectionInfo.Icon), Icon = ConnectionIcon.FromString(connectionInfo.Icon),
TabText = titleText, TabText = titleText,
@@ -162,7 +159,7 @@ namespace mRemoteNG.UI.Window
#endregion #endregion
public void ReconnectAll(IConnectionInitiator initiator) public void reconnectAll(IConnectionInitiator initiator)
{ {
var controlList = new List<InterfaceControl>(); var controlList = new List<InterfaceControl>();
try try
@@ -319,7 +316,7 @@ namespace mRemoteNG.UI.Window
{ {
var tabP = (ConnectionTab)dockContent; var tabP = (ConnectionTab)dockContent;
if (tabP.Tag == null) continue; if (tabP.Tag == null) continue;
tabP.SilentClose = true; tabP.silentClose = true;
tabP.Close(); tabP.Close();
} }
} }
@@ -801,7 +798,7 @@ namespace mRemoteNG.UI.Window
var protocolBase = sender as ProtocolBase; var protocolBase = sender as ProtocolBase;
if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return; if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return;
if (tabPage.Disposing) return; if (tabPage.Disposing) return;
tabPage.ProtocolClose = true; tabPage.protocolClose = true;
Invoke(new Action(() => tabPage.Close())); Invoke(new Action(() => tabPage.Close()));
} }

View File

@@ -1,10 +1,9 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using BrightIdeasSoftware; using BrightIdeasSoftware;
using mRemoteNG.App; using mRemoteNG.App;
using mRemoteNG.Config.Settings; using mRemoteNG.Config.Settings;
using mRemoteNG.Connection;
using mRemoteNG.Tools; using mRemoteNG.Tools;
using WeifenLuo.WinFormsUI.Docking; using WeifenLuo.WinFormsUI.Docking;
using mRemoteNG.UI.Forms; using mRemoteNG.UI.Forms;
@@ -15,15 +14,12 @@ namespace mRemoteNG.UI.Window
{ {
public partial class ExternalToolsWindow public partial class ExternalToolsWindow
{ {
private readonly IConnectionInitiator _connectionInitiator;
private readonly ExternalAppsSaver _externalAppsSaver; private readonly ExternalAppsSaver _externalAppsSaver;
private readonly ThemeManager _themeManager; private readonly ThemeManager _themeManager;
private readonly FullyObservableCollection<ExternalTool> _currentlySelectedExternalTools; private readonly FullyObservableCollection<ExternalTool> _currentlySelectedExternalTools;
public ExternalToolsWindow()
public ExternalToolsWindow(IConnectionInitiator connectionInitiator)
{ {
_connectionInitiator = connectionInitiator;
InitializeComponent(); InitializeComponent();
WindowType = WindowType.ExternalApps; WindowType = WindowType.ExternalApps;
DockPnl = new DockContent(); DockPnl = new DockContent();
@@ -181,10 +177,7 @@ namespace mRemoteNG.UI.Window
{ {
try try
{ {
var externalTool = new ExternalTool(_connectionInitiator) var externalTool = new ExternalTool(Language.strExternalToolDefaultName);
{
DisplayName = Language.strExternalToolDefaultName
};
Runtime.ExternalToolsService.ExternalTools.Add(externalTool); Runtime.ExternalToolsService.ExternalTools.Add(externalTool);
UpdateToolsListObjView(); UpdateToolsListObjView();
ToolsListObjView.SelectedObject = externalTool; ToolsListObjView.SelectedObject = externalTool;

View File

@@ -765,7 +765,7 @@
<value>https://mremoteng.org/</value> <value>https://mremoteng.org/</value>
</setting> </setting>
<setting name="SupportedUICultures" serializeAs="String"> <setting name="SupportedUICultures" serializeAs="String">
<value>cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW</value> <value>cs-CZ,de,el,en,en-US,es-AR,es,fr,hu,it,lt,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW</value>
</setting> </setting>
</mRemoteNG.Settings> </mRemoteNG.Settings>
</applicationSettings> </applicationSettings>

View File

@@ -96,9 +96,6 @@
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="Utf8Json">
<HintPath>..\packages\Utf8Json.1.3.7\lib\net45\Utf8Json.dll</HintPath>
</Reference>
<Reference Include="VncSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=61974755c7bfea7c, processorArchitecture=MSIL"> <Reference Include="VncSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=61974755c7bfea7c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>References\VncSharp.dll</HintPath> <HintPath>References\VncSharp.dll</HintPath>
@@ -252,16 +249,13 @@
<Compile Include="App\ProgramRoot.cs" /> <Compile Include="App\ProgramRoot.cs" />
<Compile Include="Connection\ConnectionInitiator.cs" /> <Compile Include="Connection\ConnectionInitiator.cs" />
<Compile Include="Connection\ConnectionsService.cs" /> <Compile Include="Connection\ConnectionsService.cs" />
<Compile Include="Connection\ConnectionStartingEvent.cs" />
<Compile Include="Connection\Converter.cs" /> <Compile Include="Connection\Converter.cs" />
<Compile Include="Connection\DefaultConnectionInfo.cs" /> <Compile Include="Connection\DefaultConnectionInfo.cs" />
<Compile Include="Connection\DefaultConnectionInheritance.cs" /> <Compile Include="Connection\DefaultConnectionInheritance.cs" />
<Compile Include="Connection\IConnectionInitiator.cs" /> <Compile Include="Connection\IConnectionInitiator.cs" />
<Compile Include="Connection\IInheritable.cs" /> <Compile Include="Connection\IInheritable.cs" />
<Compile Include="Connection\IHasParent.cs" /> <Compile Include="Connection\IHasParent.cs" />
<Compile Include="Connection\Protocol\ExternalProcessProtocolBase.cs" />
<Compile Include="Connection\Protocol\Http\Connection.Protocol.HTTPS.CertEvent.cs" /> <Compile Include="Connection\Protocol\Http\Connection.Protocol.HTTPS.CertEvent.cs" />
<Compile Include="Connection\Protocol\IFocusable.cs" />
<Compile Include="Connection\Protocol\ProtocolFactory.cs" /> <Compile Include="Connection\Protocol\ProtocolFactory.cs" />
<Compile Include="Connection\Protocol\RDP\AuthenticationLevel.cs" /> <Compile Include="Connection\Protocol\RDP\AuthenticationLevel.cs" />
<Compile Include="Connection\Protocol\RDP\AzureLoadBalanceInfoEncoder.cs" /> <Compile Include="Connection\Protocol\RDP\AzureLoadBalanceInfoEncoder.cs" />
@@ -282,6 +276,7 @@
<Compile Include="Connection\Protocol\RDP\RDPSounds.cs" /> <Compile Include="Connection\Protocol\RDP\RDPSounds.cs" />
<Compile Include="Connection\Protocol\RDP\RdpVersion.cs" /> <Compile Include="Connection\Protocol\RDP\RdpVersion.cs" />
<Compile Include="Connection\Protocol\VNC\VNCEnum.cs" /> <Compile Include="Connection\Protocol\VNC\VNCEnum.cs" />
<Compile Include="Connection\WebHelper.cs" />
<Compile Include="Credential\PlaceholderCredentialRecord.cs" /> <Compile Include="Credential\PlaceholderCredentialRecord.cs" />
<Compile Include="Credential\Repositories\CompositeRepositoryUnlocker.cs" /> <Compile Include="Credential\Repositories\CompositeRepositoryUnlocker.cs" />
<Compile Include="Credential\CredentialChangedEventArgs.cs" /> <Compile Include="Credential\CredentialChangedEventArgs.cs" />
@@ -540,7 +535,6 @@
</Compile> </Compile>
<Compile Include="UI\DialogFactory.cs" /> <Compile Include="UI\DialogFactory.cs" />
<Compile Include="UI\DisplayProperties.cs" /> <Compile Include="UI\DisplayProperties.cs" />
<Compile Include="UI\FocusHelpers\ExternalProcessFocusHelper.cs" />
<Compile Include="UI\FontOverrider.cs" /> <Compile Include="UI\FontOverrider.cs" />
<Compile Include="UI\FormExtensions.cs" /> <Compile Include="UI\FormExtensions.cs" />
<Compile Include="UI\Forms\FrmOptions.cs"> <Compile Include="UI\Forms\FrmOptions.cs">
@@ -739,7 +733,6 @@
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="UI\Panels\PanelAdder.cs" /> <Compile Include="UI\Panels\PanelAdder.cs" />
<Compile Include="UI\SystemKeyboardHook.cs" />
<Compile Include="UI\Tabs\Enums.cs" /> <Compile Include="UI\Tabs\Enums.cs" />
<Compile Include="UI\Tabs\ConnectionTab.cs"> <Compile Include="UI\Tabs\ConnectionTab.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
@@ -852,6 +845,9 @@
<EmbeddedResource Include="Resources\Language\Language.cs-CZ.resx"> <EmbeddedResource Include="Resources\Language\Language.cs-CZ.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Resources\Language\Language.lt.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Language\Language.ja-JP.resx"> <EmbeddedResource Include="Resources\Language\Language.ja-JP.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>