Compare commits

..

14 Commits

Author SHA1 Message Date
David Sparer
7305bc4441 Merge branch 'develop' into bug/ssh_focus
# Conflicts:
#	mRemoteV1/UI/Forms/frmMain.cs
2019-09-01 18:58:16 -05:00
David Sparer
2c47c857ec fixed array out of bounds exception when clicking in tab area 2019-09-01 17:16:07 -05:00
David Sparer
19f1770eda minor cleanup 2019-09-01 17:15:00 -05:00
David Sparer
40e878a517 resolved focus bug on first-connect 2019-09-01 16:38:11 -05:00
David Sparer
d09e9b10a0 fixed issue with mrng being in weird positions in the alt-tab lineup when extapp has focus 2019-09-01 16:07:58 -05:00
David Sparer
0d727338f0 moved a number of focus logic window events out of frmmain 2019-09-01 14:54:49 -05:00
David Sparer
e9838960fa improved ability to determine if external proc has focus 2019-09-01 12:30:11 -05:00
David Sparer
74611e9db6 refactored some alt-tab focus logic to a new class 2019-08-25 17:19:06 -05:00
David Sparer
f7dc0918eb fixed most focus issues when working with putty
still need to resolve refocusing putty in some cases
2019-08-25 15:59:51 -05:00
David Sparer
26d9e3c2ff debug putty focus issues 2019-08-25 10:42:13 -05:00
David Sparer
53c534aa93 use a single instance of IConnectionInitiator everywhere 2019-08-25 10:42:13 -05:00
David Sparer
dfd02e7b9a removed unused webhelper class 2019-08-25 10:42:13 -05:00
David Sparer
65eac21471 minor cleanup 2019-08-25 10:42:13 -05:00
David Sparer
5f776a3525 minor cleanup of the connection tab class 2019-08-25 10:42:13 -05:00
52 changed files with 2486 additions and 936 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).
## [1.77.1] - 2019-09-02
## [Unreleased]
### Added
- #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
@@ -11,20 +11,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- #1385: Added option to start mRemoteNG minimized
- #826: Allow selecting RDP version to use when connecting
### Changed
- #1544: Improved Polish translations
- #1518: Inheritance is no longer automatically enabled when importing nodes from Active Directory
- #1468: Improved mRemoteNG startup time
- #1443: Chinese (simplified) 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
- #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.
- Removed the "Automatically get session info" from the advanced options screen since it is no longer used.
### 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
- #1439: Searching in hosts tree loses first keystroke
- #1428: Fixed a rare error when checking for FIPS

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,18 @@
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,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.UI.Window;
@@ -6,7 +8,7 @@ namespace mRemoteNG.Connection
{
public interface IConnectionInitiator
{
IEnumerable<string> ActiveConnections { get; }
IEnumerable<ProtocolBase> ActiveConnections { get; }
void OpenConnection(
ContainerInfo containerInfo,
@@ -19,5 +21,7 @@ namespace mRemoteNG.Connection
ConnectionWindow conForm = null);
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 System;
using System.Drawing;
@@ -25,6 +25,8 @@ namespace mRemoteNG.Connection
Location = new Point(0, 0);
Size = Parent.Size;
Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
GotFocus += OnGotFocus;
LostFocus += OnLostFocus;
InitializeComponent();
}
catch (Exception ex)
@@ -35,6 +37,16 @@ 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)
{
if (!(DockPnl.ActiveDocument is ConnectionTab ct)) return null;

View File

@@ -0,0 +1,120 @@
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

@@ -0,0 +1,11 @@
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.Drawing;
using System.Threading;
@@ -9,7 +9,7 @@ using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol
{
public class IntegratedProgram : ProtocolBase
public class IntegratedProgram : ExternalProcessProtocolBase
{
#region Private Fields

View File

@@ -63,6 +63,12 @@ namespace mRemoteNG.Connection.Protocol
public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(2000);
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)
{
Name = name;
@@ -335,8 +341,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (!disposing) return;
if(tmrReconnect != null)
tmrReconnect.Dispose();
tmrReconnect?.Dispose();
}
public void Dispose()

View File

@@ -1,4 +1,4 @@
using mRemoteNG.App;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
@@ -14,27 +14,22 @@ using System.Windows.Forms;
namespace mRemoteNG.Connection.Protocol
{
public class PuttyBase : ProtocolBase
public class PuttyBase : ExternalProcessProtocolBase
{
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
private bool _isPuttyNg;
private readonly DisplayProperties _display = new DisplayProperties();
#region Public Properties
protected Putty_Protocol PuttyProtocol { 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 bool Focused
{
get { return NativeMethods.GetForegroundWindow() == PuttyHandle; }
get { return NativeMethods.GetForegroundWindow() == ProcessHandle; }
}
#endregion
@@ -54,111 +49,40 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
_isPuttyNg = PuttyTypeDetector.GetPuttyType() == PuttyTypeDetector.PuttyType.PuttyNg;
base.Connect();
var arguments = BuildPuttyCommandLineArguments(InterfaceControl.Info);
PuttyProcess = new Process
ProtocolProcess = new Process
{
StartInfo =
{
UseShellExecute = false,
FileName = PuttyPath
}
FileName = PuttyPath,
Arguments = arguments.ToString()
},
EnableRaisingEvents = true
};
var arguments = new CommandLineArguments {EscapeForShell = false};
ProtocolProcess.Exited += ProcessExited;
arguments.Add("-load", InterfaceControl.Info.PuttySession);
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);
ProtocolProcess.Start();
ProtocolProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount;
while (PuttyHandle.ToInt32() == 0 &
while (ProcessHandle.ToInt32() == 0 &
Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
{
if (_isPuttyNg)
{
PuttyHandle = NativeMethods.FindWindowEx(
InterfaceControl.Handle, new IntPtr(0), null, null);
ProcessHandle = NativeMethods.FindWindowEx(InterfaceControl.Handle, new IntPtr(0), null, null);
}
else
{
PuttyProcess.Refresh();
PuttyHandle = PuttyProcess.MainWindowHandle;
ProtocolProcess.Refresh();
ProcessHandle = ProtocolProcess.MainWindowHandle;
}
if (PuttyHandle.ToInt32() == 0)
if (ProcessHandle.ToInt32() == 0)
{
Thread.Sleep(0);
}
@@ -166,21 +90,20 @@ namespace mRemoteNG.Connection.Protocol
if (!_isPuttyNg)
{
NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle);
NativeMethods.SetParent(ProcessHandle, InterfaceControl.Handle);
}
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyHandle, PuttyHandle), true);
string.Format(Language.strPuttyHandle, ProcessHandle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle),
string.Format(Language.strPuttyTitle, ProtocolProcess.MainWindowTitle),
true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
string.Format(Language.strPuttyParentHandle,
InterfaceControl.Parent.Handle), true);
Resize(this, new EventArgs());
base.Connect();
return true;
}
catch (Exception ex)
@@ -192,18 +115,102 @@ 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()
{
try
{
NativeMethods.SetForegroundWindow(PuttyHandle);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
Language.strPuttyFocusFailed + Environment.NewLine + ex.Message,
true);
}
//try
//{
// if (NativeMethods.GetForegroundWindow() == PuttyHandle)
// {
// Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Putty window already focused, ignoring focus request '{InterfaceControl.Info.Name}' (pid:{PuttyProcess.Id})");
// return;
// }
// NativeMethods.SetForegroundWindow(PuttyHandle);
// 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)
@@ -216,14 +223,14 @@ namespace mRemoteNG.Connection.Protocol
if (_isPuttyNg)
{
// PuTTYNG 0.70.0.1 and later doesn't have any window borders
NativeMethods.MoveWindow(PuttyHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true);
NativeMethods.MoveWindow(ProcessHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true);
}
else
{
var scaledFrameBorderHeight = _display.ScaleHeight(SystemInformation.FrameBorderSize.Height);
var scaledFrameBorderWidth = _display.ScaleWidth(SystemInformation.FrameBorderSize.Width);
NativeMethods.MoveWindow(PuttyHandle, -scaledFrameBorderWidth,
NativeMethods.MoveWindow(ProcessHandle, -scaledFrameBorderWidth,
-(SystemInformation.CaptionHeight + scaledFrameBorderHeight),
InterfaceControl.Width + scaledFrameBorderWidth * 2,
InterfaceControl.Height + SystemInformation.CaptionHeight +
@@ -243,9 +250,9 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
if (PuttyProcess.HasExited == false)
if (ProtocolProcess.HasExited == false)
{
PuttyProcess.Kill();
ProtocolProcess.Kill();
}
}
catch (Exception ex)
@@ -257,7 +264,7 @@ namespace mRemoteNG.Connection.Protocol
try
{
PuttyProcess.Dispose();
ProtocolProcess.Dispose();
}
catch (Exception ex)
{
@@ -273,8 +280,8 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
NativeMethods.PostMessage(PuttyHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, (IntPtr)0);
NativeMethods.SetForegroundWindow(PuttyHandle);
NativeMethods.PostMessage(ProcessHandle, NativeMethods.WM_SYSCOMMAND, (IntPtr)IDM_RECONF, IntPtr.Zero);
Focus();
}
catch (Exception ex)
{
@@ -284,6 +291,14 @@ 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
#region Enums

View File

@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Timers;
using System.Windows.Forms;
@@ -35,6 +38,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
private readonly FrmMain _frmMain = FrmMain.Default;
protected virtual RdpVersion RdpProtocolVersion => RdpVersion.Rdc6;
private AxHost AxHost => (AxHost)Control;
private readonly NativeMethods.EnumWindowsProc _enumWindowsProc;
#region Properties
@@ -101,6 +105,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
{
_displayProperties = new DisplayProperties();
tmrReconnect.Elapsed += tmrReconnect_Elapsed;
_enumWindowsProc = LpEnumFunc;
}
#endregion
@@ -243,17 +248,54 @@ namespace mRemoteNG.Connection.Protocol.RDP
public override void Focus()
{
var result = new List<IntPtr>();
var listHandle = GCHandle.Alloc(result);
try
{
if (Control.ContainsFocus == false)
{
Control.Focus();
//AxHost.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)
{
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>
@@ -672,6 +714,9 @@ namespace mRemoteNG.Connection.Protocol.RDP
_rdpClient.OnDisconnected += RDPEvent_OnDisconnected;
_rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode;
_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)
{
@@ -748,7 +793,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
private void RdpClient_GotFocus(object sender, EventArgs e)
{
((ConnectionTab)Control.Parent.Parent).Focus();
//((ConnectionTab)Control.Parent.Parent).Focus();
}
#endregion

View File

@@ -1,23 +0,0 @@
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)
{
var textToPrint = $"{message.Class}: {message.Text}";
var textToPrint = $"[{message.Date.ToString("O")}] {message.Class}: {message.Text}";
Debug.Print(textToPrint);
}
}

View File

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

View File

@@ -12,7 +12,7 @@ namespace mRemoteNG {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -2583,8 +2583,8 @@ namespace mRemoteNG {
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[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-TR,zh-CN,zh-TW")]
[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-" +
"TR,zh-CN,zh-TW")]
public string SupportedUICultures {
get {
return ((string)(this["SupportedUICultures"]));

View File

@@ -642,7 +642,7 @@
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="SupportedUICultures" Type="System.String" Scope="Application">
<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>
<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>
</Setting>
<Setting Name="ThemingActive" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>

View File

@@ -1,345 +0,0 @@
<?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.Linq;
using WeifenLuo.WinFormsUI.Docking;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,60 @@
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,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.App.Info;
@@ -6,6 +7,7 @@ using mRemoteNG.Config;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Messages;
using mRemoteNG.UI.TaskDialog;
using WeifenLuo.WinFormsUI.Docking;
@@ -13,81 +15,73 @@ namespace mRemoteNG.UI.Tabs
{
public partial class ConnectionTab : DockContent
{
public InterfaceControl InterfaceControl => Tag as InterfaceControl;
/// <summary>
///Silent close ignores the popup asking for confirmation
/// </summary>
public bool silentClose { get; set; }
public bool SilentClose { get; set; }
/// <summary>
/// Protocol close ignores the interface controller cleanup and the user confirmation dialog
/// </summary>
public bool protocolClose { get; set; }
public bool ProtocolClose { get; set; }
public ConnectionTab()
{
InitializeComponent();
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)
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Tab received focused: '{TabText}'");
TabHelper.Instance.CurrentTab = this;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (!protocolClose)
if (!ProtocolClose)
{
if (!silentClose)
if (!SilentClose)
{
if (Settings.Default.ConfirmCloseConnection == (int)ConfirmCloseEnum.All)
{
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();
}
ShowCloseConnectionTabPrompt(e);
}
else
{
// close without the confirmation prompt...
((InterfaceControl)Tag)?.Protocol.Close();
InterfaceControl?.Protocol.Close();
}
}
else
{
((InterfaceControl)Tag)?.Protocol.Close();
InterfaceControl?.Protocol.Close();
}
}
base.OnFormClosing(e);
}
#region HelperFunctions
public void RefreshInterfaceController()
{
try
{
var interfaceControl = Tag as InterfaceControl;
if (interfaceControl?.Info.Protocol == ProtocolType.VNC)
((ProtocolVNC)interfaceControl.Protocol).RefreshScreen();
if (InterfaceControl?.Info.Protocol == ProtocolType.VNC)
((ProtocolVNC)InterfaceControl.Protocol).RefreshScreen();
}
catch (Exception ex)
{
@@ -95,6 +89,28 @@ namespace mRemoteNG.UI.Tabs
}
}
#endregion
private void ShowCloseConnectionTabPrompt(FormClosingEventArgs 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?.Protocol.Close();
}
}
}
}

View File

@@ -1088,11 +1088,22 @@ namespace mRemoteNG.UI.Tabs
protected override void OnMouseDown(MouseEventArgs e)
{
App.Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Mouse down");
base.OnMouseDown(e);
// suspend drag if mouse is down on active close button.
m_suspendDrag = ActiveCloseHitTest(e.Location);
if (!IsMouseDown)
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)
@@ -1149,6 +1160,7 @@ namespace mRemoteNG.UI.Tabs
protected override void OnMouseClick(MouseEventArgs e)
{
App.Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, "Mouse click");
base.OnMouseClick(e);
if (e.Button != MouseButtons.Left || Appearance != DockPane.AppearanceStyle.Document)
return;

View File

@@ -4,12 +4,18 @@ using System;
namespace mRemoteNG.UI.Tabs
{
class TabHelper
public class TabHelper
{
private static readonly Lazy<TabHelper> lazyHelper = new Lazy<TabHelper>(() => new TabHelper());
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()
{
}
@@ -21,10 +27,16 @@ namespace mRemoteNG.UI.Tabs
get => currentTab;
set
{
if (currentTab == value)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Tab already current: '{currentTab.TabText}'");
return;
}
currentTab = value;
findCurrentPanel();
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg,
"Tab got focused: " + currentTab.TabText);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Current tab changed: '{currentTab.TabText}'");
RaiseActiveConnectionTabChangedEvent();
}
}
@@ -36,7 +48,7 @@ namespace mRemoteNG.UI.Tabs
currentForm = currentForm.Parent;
}
if (currentForm != null)
if (currentForm != null && CurrentPanel != currentForm)
CurrentPanel = (ConnectionWindow)currentForm;
}
@@ -47,10 +59,31 @@ namespace mRemoteNG.UI.Tabs
get => currentPanel;
set
{
if (currentPanel == value)
return;
currentPanel = value;
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg,
"Panel got focused: " + currentPanel.TabText);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.DebugMsg, $"Current panel changed: '{currentPanel.TabText}'");
RaiseActivePanelChangedEvent();
}
}
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
{
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private readonly IConnectionInitiator _connectionInitiator;
private ThemeManager _themeManager;
private bool sortedAz = true;
@@ -33,12 +33,14 @@ namespace mRemoteNG.UI.Window
set { olvConnections = value; }
}
public ConnectionTreeWindow() : this(new DockContent())
public ConnectionTreeWindow(IConnectionInitiator connectionInitiator)
: this(new DockContent(), connectionInitiator)
{
}
public ConnectionTreeWindow(DockContent panel)
public ConnectionTreeWindow(DockContent panel, IConnectionInitiator connectionInitiator)
{
_connectionInitiator = connectionInitiator;
WindowType = WindowType.Tree;
DockPnl = panel;
InitializeComponent();

View File

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

View File

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

View File

@@ -765,7 +765,7 @@
<value>https://mremoteng.org/</value>
</setting>
<setting name="SupportedUICultures" serializeAs="String">
<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>
<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>
</setting>
</mRemoteNG.Settings>
</applicationSettings>

View File

@@ -96,6 +96,9 @@
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<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">
<SpecificVersion>False</SpecificVersion>
<HintPath>References\VncSharp.dll</HintPath>
@@ -249,13 +252,16 @@
<Compile Include="App\ProgramRoot.cs" />
<Compile Include="Connection\ConnectionInitiator.cs" />
<Compile Include="Connection\ConnectionsService.cs" />
<Compile Include="Connection\ConnectionStartingEvent.cs" />
<Compile Include="Connection\Converter.cs" />
<Compile Include="Connection\DefaultConnectionInfo.cs" />
<Compile Include="Connection\DefaultConnectionInheritance.cs" />
<Compile Include="Connection\IConnectionInitiator.cs" />
<Compile Include="Connection\IInheritable.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\IFocusable.cs" />
<Compile Include="Connection\Protocol\ProtocolFactory.cs" />
<Compile Include="Connection\Protocol\RDP\AuthenticationLevel.cs" />
<Compile Include="Connection\Protocol\RDP\AzureLoadBalanceInfoEncoder.cs" />
@@ -276,7 +282,6 @@
<Compile Include="Connection\Protocol\RDP\RDPSounds.cs" />
<Compile Include="Connection\Protocol\RDP\RdpVersion.cs" />
<Compile Include="Connection\Protocol\VNC\VNCEnum.cs" />
<Compile Include="Connection\WebHelper.cs" />
<Compile Include="Credential\PlaceholderCredentialRecord.cs" />
<Compile Include="Credential\Repositories\CompositeRepositoryUnlocker.cs" />
<Compile Include="Credential\CredentialChangedEventArgs.cs" />
@@ -535,6 +540,7 @@
</Compile>
<Compile Include="UI\DialogFactory.cs" />
<Compile Include="UI\DisplayProperties.cs" />
<Compile Include="UI\FocusHelpers\ExternalProcessFocusHelper.cs" />
<Compile Include="UI\FontOverrider.cs" />
<Compile Include="UI\FormExtensions.cs" />
<Compile Include="UI\Forms\FrmOptions.cs">
@@ -733,6 +739,7 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="UI\Panels\PanelAdder.cs" />
<Compile Include="UI\SystemKeyboardHook.cs" />
<Compile Include="UI\Tabs\Enums.cs" />
<Compile Include="UI\Tabs\ConnectionTab.cs">
<SubType>Form</SubType>
@@ -845,9 +852,6 @@
<EmbeddedResource Include="Resources\Language\Language.cs-CZ.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Language\Language.lt.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Language\Language.ja-JP.resx">
<SubType>Designer</SubType>
</EmbeddedResource>