From ff2bbcf6502a9ed74c01744ce81b13ada5f5651d Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 14 Oct 2013 18:30:55 -0500 Subject: [PATCH 01/18] Fix issue MR-566 - Typo in German UI Automatic Update Settings --- CHANGELOG.TXT | 1 + mRemoteV1/Language/Language.de.resx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index a90fe578e..1adb897f5 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,5 +1,6 @@ 1.71 (XXXX-XX-XX): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' + Fixed issue MR-566 - Typo in German UI Automatic Update Settings 1.71 Release Candidate 1 (2013-10-01): Fixed issue MR-495 - Having a negative range in port scan creates memory exhaustion. diff --git a/mRemoteV1/Language/Language.de.resx b/mRemoteV1/Language/Language.de.resx index d5501e73b..cf6bc94c6 100644 --- a/mRemoteV1/Language/Language.de.resx +++ b/mRemoteV1/Language/Language.de.resx @@ -163,7 +163,7 @@ Einstellungen jetzt anpassen - Verwende die empflohlenen Einstellungen + Verwende die empfohlenen Einstellungen {0} kann automatisch nach Updates suchen die neue Funktionen und Bug Fixes enthalten können. Es wird empfohlen, dass Sie {0} erlauben wöchentlich nach Updates zu suchen. From 42bcf8db31dbf02674dea681bc9f3d2dcf304ff1 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 14 Oct 2013 18:31:31 -0500 Subject: [PATCH 02/18] Fix typo in Portuguese translation. --- mRemoteV1/Language/Language.pt.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/Language/Language.pt.resx b/mRemoteV1/Language/Language.pt.resx index cb60c78cb..afd9dc1aa 100644 --- a/mRemoteV1/Language/Language.pt.resx +++ b/mRemoteV1/Language/Language.pt.resx @@ -606,7 +606,7 @@ Descrição do erro: {1} Erros - O arquivo de inicialização de ligação não pôde ser carregado.{0}{0}(2){0}{3}{0}{0}A fim de evitar perda de dados, {1} vai sair agora. + O arquivo de inicialização de ligação não pôde ser carregado.{0}{0}{2}{0}{3}{0}{0}A fim de evitar perda de dados, {1} vai sair agora. VerifyDatabaseVersion (Config.Connections.Save) falhou. {0} From 9ebce266ecfd7d4e8a77a11042e232e37f3892ca Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 14 Oct 2013 22:42:34 -0500 Subject: [PATCH 03/18] Fix issue MR-565 - Double Folder keep heritage on the initial Folder --- CHANGELOG.TXT | 1 + mRemoteV1/Connection/Connection.Info.vb | 11 ++++++----- mRemoteV1/Tree/Tree.Node.vb | 10 ++++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 1adb897f5..a4ca5ff62 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,5 +1,6 @@ 1.71 (XXXX-XX-XX): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' + Fixed issue MR-565 - Double Folder keep heritage on the initial Folder Fixed issue MR-566 - Typo in German UI Automatic Update Settings 1.71 Release Candidate 1 (2013-10-01): diff --git a/mRemoteV1/Connection/Connection.Info.vb b/mRemoteV1/Connection/Connection.Info.vb index 2897e4102..fc18a6619 100644 --- a/mRemoteV1/Connection/Connection.Info.vb +++ b/mRemoteV1/Connection/Connection.Info.vb @@ -1531,9 +1531,10 @@ Namespace Connection #End Region #Region "Methods" - Public Function Copy() As Connection.Info - Dim newConnectionInfo As Connection.Info = MemberwiseClone() - newConnectionInfo._OpenConnections = New Connection.Protocol.List + Public Function Copy() As Info + Dim newConnectionInfo As Info = MemberwiseClone() + newConnectionInfo.ConstantID = Tools.Misc.CreateConstantID() + newConnectionInfo._OpenConnections = New Protocol.List Return newConnectionInfo End Function @@ -1597,8 +1598,8 @@ Namespace Connection End If End Sub - Public Function Copy() As Connection.Info.Inheritance - Return Me.MemberwiseClone + Public Function Copy() As Inheritance + Return MemberwiseClone() End Function Public Sub TurnOnInheritanceCompletely() diff --git a/mRemoteV1/Tree/Tree.Node.vb b/mRemoteV1/Tree/Tree.Node.vb index f82ce8fe9..17ab8e790 100644 --- a/mRemoteV1/Tree/Tree.Node.vb +++ b/mRemoteV1/Tree/Tree.Node.vb @@ -305,9 +305,9 @@ Namespace Tree Public Shared Sub CloneNode(ByVal oldTreeNode As TreeNode, Optional ByVal parentNode As TreeNode = Nothing) Try If GetNodeType(oldTreeNode) = Type.Connection Then - Dim oldConnectionInfo As Connection.Info = oldTreeNode.Tag + Dim oldConnectionInfo As Connection.Info = DirectCast(oldTreeNode.Tag, Connection.Info) - Dim newConnectionInfo As Connection.Info = oldConnectionInfo.Copy + Dim newConnectionInfo As Connection.Info = oldConnectionInfo.Copy() Dim newInheritance As Connection.Info.Inheritance = oldConnectionInfo.Inherit.Copy() newInheritance.Parent = newConnectionInfo newConnectionInfo.Inherit = newInheritance @@ -332,8 +332,10 @@ Namespace Tree parentNode.Nodes.Add(newTreeNode) End If ElseIf GetNodeType(oldTreeNode) = Type.Container Then - Dim newContainerInfo As Container.Info = TryCast(oldTreeNode.Tag, Container.Info).Copy - Dim newConnectionInfo As Connection.Info = TryCast(oldTreeNode.Tag, Container.Info).ConnectionInfo.Copy + Dim oldContainerInfo As Container.Info = DirectCast(oldTreeNode.Tag, Container.Info) + + Dim newContainerInfo As Container.Info = oldContainerInfo.Copy() + Dim newConnectionInfo As Connection.Info = oldContainerInfo.ConnectionInfo.Copy() newContainerInfo.ConnectionInfo = newConnectionInfo Dim newTreeNode As New TreeNode(newContainerInfo.Name) From 81d150f80ae95f1bae508fd0f508e8884f53d183 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 14 Oct 2013 22:47:48 -0500 Subject: [PATCH 04/18] Fix duplicated folders possibly being named "New Connection" instead of the original folder's name --- CHANGELOG.TXT | 1 + mRemoteV1/UI/UI.Window.Tree.vb | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index a4ca5ff62..d3be2cd05 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -2,6 +2,7 @@ Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' Fixed issue MR-565 - Double Folder keep heritage on the initial Folder Fixed issue MR-566 - Typo in German UI Automatic Update Settings + Fixed duplicated folders possibly being named "New Connection" instead of the original folder's name 1.71 Release Candidate 1 (2013-10-01): Fixed issue MR-495 - Having a negative range in port scan creates memory exhaustion. diff --git a/mRemoteV1/UI/UI.Window.Tree.vb b/mRemoteV1/UI/UI.Window.Tree.vb index b3412485b..1551b980f 100644 --- a/mRemoteV1/UI/UI.Window.Tree.vb +++ b/mRemoteV1/UI/UI.Window.Tree.vb @@ -1088,6 +1088,7 @@ Namespace UI End If newContainerInfo.ConnectionInfo = New mRemoteNG.Connection.Info(newContainerInfo) + newContainerInfo.ConnectionInfo.Name = newNode.Text ' We can only inherit from a container node, not the root node or connection nodes If mRemoteNG.Tree.Node.GetNodeType(parentNode) = mRemoteNG.Tree.Node.Type.Container Then From 3cb8784996e4569d59030f20946c8061e01dee70 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 14 Oct 2013 22:48:10 -0500 Subject: [PATCH 05/18] Minor code cleanup. --- mRemoteV1/Connection/Connection.Info.vb | 6 +++--- mRemoteV1/Container/Container.Info.vb | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mRemoteV1/Connection/Connection.Info.vb b/mRemoteV1/Connection/Connection.Info.vb index fc18a6619..f3bf484d1 100644 --- a/mRemoteV1/Connection/Connection.Info.vb +++ b/mRemoteV1/Connection/Connection.Info.vb @@ -8,17 +8,17 @@ Namespace Connection Public Class Info #Region "Properties" #Region "1 Display" - Private _Name As String = My.Language.strNewConnection + Private _name As String = My.Language.strNewConnection _ Public Overridable Property Name() As String Get - Return Me._Name + Return _name End Get Set(ByVal value As String) - Me._Name = value + _name = value End Set End Property diff --git a/mRemoteV1/Container/Container.Info.vb b/mRemoteV1/Container/Container.Info.vb index ecadde128..e6ae7aad4 100644 --- a/mRemoteV1/Container/Container.Info.vb +++ b/mRemoteV1/Container/Container.Info.vb @@ -6,7 +6,6 @@ Namespace Container _ Public Class Info #Region "Properties" - Private _Name As String = "New Container" _ Public Property Name() As String Get - Return Me._ConnectionInfo.Name + Return ConnectionInfo.Name End Get Set(ByVal value As String) - Me._ConnectionInfo.Name = value + ConnectionInfo.Name = value End Set End Property From 62feba1691163603cf47197d52196a588052513f Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Wed, 16 Oct 2013 17:08:10 -0500 Subject: [PATCH 06/18] Update CHANGELOG.TXT for 1.71 RC2. --- CHANGELOG.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index d3be2cd05..22fb2f397 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,4 +1,4 @@ -1.71 (XXXX-XX-XX): +1.71 (2013-10-16): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' Fixed issue MR-565 - Double Folder keep heritage on the initial Folder Fixed issue MR-566 - Typo in German UI Automatic Update Settings From 8273bdf70f4acb42fa07cb044e492e9a9df067f8 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 21 Oct 2013 18:55:59 -0500 Subject: [PATCH 07/18] Remove invalid "Site" configuration option from PuTTY Saved Sessions --- CHANGELOG.TXT | 1 + mRemoteV1/Connection/PuttySession.Info.vb | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 083ce6c71..574d6b553 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -2,6 +2,7 @@ Fixed issue MR-141 - Add a default protocol option Fixed issue MR-367 - Make the 'Connect' button on the 'Quick Connect' toolbar a forced dropdown Fixed misleading log messages about RD Gateway support. + Removed invalid "Site" configuration option from PuTTY Saved Sessions 1.71 (2013-10-16): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' diff --git a/mRemoteV1/Connection/PuttySession.Info.vb b/mRemoteV1/Connection/PuttySession.Info.vb index 2acd6419e..6258f034a 100644 --- a/mRemoteV1/Connection/PuttySession.Info.vb +++ b/mRemoteV1/Connection/PuttySession.Info.vb @@ -100,6 +100,7 @@ Namespace Connection #End Region #Region "IComponent" + _ Public Property Site() As ISite Implements IComponent.Site Get Return New PropertyGridCommandSite(Me) From a6fa6e19d0a7f142c07f8b4722687a5ea1fd21d5 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 21 Oct 2013 20:38:39 -0500 Subject: [PATCH 08/18] Fix PuTTY Saved Sessions still showing if all saved sessions are removed --- CHANGELOG.TXT | 1 + mRemoteV1/Config/PuttySessions.vb | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 574d6b553..892097bc0 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -3,6 +3,7 @@ Fixed issue MR-367 - Make the 'Connect' button on the 'Quick Connect' toolbar a forced dropdown Fixed misleading log messages about RD Gateway support. Removed invalid "Site" configuration option from PuTTY Saved Sessions + Fixed PuTTY Saved Sessions still showing if all saved sessions are removed 1.71 (2013-10-16): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' diff --git a/mRemoteV1/Config/PuttySessions.vb b/mRemoteV1/Config/PuttySessions.vb index 05d46df07..d0248912b 100644 --- a/mRemoteV1/Config/PuttySessions.vb +++ b/mRemoteV1/Config/PuttySessions.vb @@ -23,7 +23,14 @@ Namespace Config End If Dim savedSessions As New List(Of Connection.Info)(LoadSessions()) - If savedSessions Is Nothing OrElse savedSessions.Count = 0 Then Return + If savedSessions Is Nothing Or savedSessions.Count = 0 Then + If _rootTreeNode IsNot Nothing AndAlso treeView.Nodes.Contains(_rootTreeNode) Then + treeView.BeginUpdate() + treeView.Nodes.Remove(_rootTreeNode) + treeView.EndUpdate() + End If + Return + End If Dim puttyRootInfo As New Root.PuttySessions.Info() If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsName) Then From 8c61e95a5bf0f7433757f536caff35b49138418f Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 21 Oct 2013 20:43:21 -0500 Subject: [PATCH 09/18] Reword CHANGELOG.TXT. --- CHANGELOG.TXT | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 892097bc0..cc4007e1a 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,6 +1,6 @@ 1.72: - Fixed issue MR-141 - Add a default protocol option - Fixed issue MR-367 - Make the 'Connect' button on the 'Quick Connect' toolbar a forced dropdown + Added feature MR-141 - Add a default protocol option + Made improvement MR-367 - Make the 'Connect' button on the 'Quick Connect' toolbar a forced dropdown Fixed misleading log messages about RD Gateway support. Removed invalid "Site" configuration option from PuTTY Saved Sessions Fixed PuTTY Saved Sessions still showing if all saved sessions are removed From 13c1d049fc7b92c7a5be1c23bd85423fe03da0b8 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Fri, 25 Oct 2013 00:56:28 -0500 Subject: [PATCH 10/18] Fix issue MR-574 - Crash when retrieving RDP session list if eolwtscom.dll is not registered --- CHANGELOG.TXT | 5 +- .../Connection/Connection.Protocol.RDP.vb | 161 ++++++++---------- mRemoteV1/UI/UI.Window.Sessions.vb | 20 +-- 3 files changed, 84 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 22fb2f397..1c8654a72 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,4 +1,7 @@ -1.71 (2013-10-16): +1.71 (XXXX-XX-XX): + Fixed issue MR-574 - Crash when retrieving RDP session list if eolwtscom.dll is not registered + +1.71 Release Candidate 2 (2013-10-16): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' Fixed issue MR-565 - Double Folder keep heritage on the initial Folder Fixed issue MR-566 - Typo in German UI Automatic Update Settings diff --git a/mRemoteV1/Connection/Connection.Protocol.RDP.vb b/mRemoteV1/Connection/Connection.Protocol.RDP.vb index 08e90cebb..ed767aadc 100644 --- a/mRemoteV1/Connection/Connection.Protocol.RDP.vb +++ b/mRemoteV1/Connection/Connection.Protocol.RDP.vb @@ -635,77 +635,91 @@ Namespace Connection #Region "Terminal Sessions" Public Class TerminalSessions - Dim oWTSCOM As New WTSCOM - Dim oWTSSessions As New WTSSessions - Dim oWTSSession As New WTSSession - Public ServerHandle As Long + Private ReadOnly _wtsCom As WTSCOM - Public Function OpenConnection(ByVal SrvName As String) As Boolean + Public Sub New() Try - ServerHandle = oWTSCOM.WTSOpenServer(SrvName) - - If ServerHandle <> 0 Then - Return True - End If + _wtsCom = New WTSCOM Catch ex As Exception - MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, My.Language.strRdpOpenConnectionFailed & vbNewLine & ex.Message, True) - End Try - - Return False - End Function - - Public Sub CloseConnection(ByVal SrvHandle As Long) - Try - oWTSCOM.WTSCloseServer(ServerHandle) - ServerHandle = 0 - Catch ex As Exception - MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, My.Language.strRdpCloseConnectionFailed & vbNewLine & ex.Message, True) + MessageCollector.AddExceptionMessage("TerminalSessions.New() failed.", ex, MessageClass.ErrorMsg, True) End Try End Sub - Public Function GetSessions() As Sessions - Dim colSessions As New Sessions + Public Function OpenConnection(ByVal hostname As String) As Long + If _wtsCom Is Nothing Then Return 0 Try - oWTSSessions = oWTSCOM.WTSEnumerateSessions(ServerHandle) + Return _wtsCom.WTSOpenServer(hostname) + Catch ex As Exception + MessageCollector.AddExceptionMessage(My.Language.strRdpOpenConnectionFailed, ex, MessageClass.ErrorMsg, True) + End Try + End Function - Dim SessionID As Long - Dim SessionUser As String - Dim SessionState As Long - Dim SessionName As String + Public Sub CloseConnection(ByVal serverHandle As Long) + If _wtsCom Is Nothing Then Return - For Each oWTSSession In oWTSSessions - SessionID = oWTSSession.SessionId - SessionUser = oWTSCOM.WTSQuerySessionInformation(ServerHandle, oWTSSession.SessionId, 5) 'WFUsername = 5 - SessionState = oWTSSession.State & vbCrLf - SessionName = oWTSSession.WinStationName & vbCrLf + Try + _wtsCom.WTSCloseServer(serverHandle) + Catch ex As Exception + MessageCollector.AddExceptionMessage(My.Language.strRdpCloseConnectionFailed, ex, MessageClass.ErrorMsg, True) + End Try + End Sub - If SessionUser <> "" Then - If SessionState = 0 Then - colSessions.Add(SessionID, My.Language.strActive, SessionUser, SessionName) + Public Function GetSessions(ByVal serverHandle As Long) As SessionsCollection + If _wtsCom Is Nothing Then Return New SessionsCollection() + + Dim sessions As New SessionsCollection() + + Try + Dim wtsSessions As WTSSessions = _wtsCom.WTSEnumerateSessions(serverHandle) + + Dim sessionId As Long + Dim sessionUser As String + Dim sessionState As Long + Dim sessionName As String + + For Each wtsSession As WTSSession In wtsSessions + sessionId = wtsSession.SessionId + sessionUser = _wtsCom.WTSQuerySessionInformation(serverHandle, wtsSession.SessionId, 5) ' WFUsername = 5 + sessionState = wtsSession.State & vbCrLf + sessionName = wtsSession.WinStationName & vbCrLf + + If Not String.IsNullOrEmpty(sessionUser) Then + If sessionState = 0 Then + sessions.Add(sessionId, My.Language.strActive, sessionUser, sessionName) Else - colSessions.Add(SessionID, My.Language.strInactive, SessionUser, SessionName) + sessions.Add(sessionId, My.Language.strInactive, sessionUser, sessionName) End If End If Next Catch ex As Exception - MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, My.Language.strRdpGetSessionsFailed & vbNewLine & ex.Message, True) + MessageCollector.AddExceptionMessage(My.Language.strRdpGetSessionsFailed, ex, MessageClass.ErrorMsg, True) End Try - Return colSessions + Return sessions End Function - Public Function KillSession(ByVal SessionID As Long) As Boolean - Return oWTSCOM.WTSLogoffSession(ServerHandle, SessionID, True) + Public Function KillSession(ByVal serverHandle As Long, ByVal sessionId As Long) As Boolean + If _wtsCom Is Nothing Then Return False + + Dim result As Boolean = False + + Try + result = _wtsCom.WTSLogoffSession(serverHandle, sessionId, True) + Catch ex As Exception + MessageCollector.AddExceptionMessage("TerminalSessions.KillSession() failed.", ex, MessageClass.ErrorMsg, True) + End Try + + Return result End Function End Class - Public Class Sessions + Public Class SessionsCollection Inherits CollectionBase - Default Public ReadOnly Property Items(ByVal Index As Integer) As Session + Default Public ReadOnly Property Items(ByVal index As Integer) As Session Get - Return CType(List.Item(Index), Session) + Return CType(List.Item(index), Session) End Get End Property @@ -715,23 +729,23 @@ Namespace Connection End Get End Property - Public Function Add(ByVal SessionID As Long, ByVal SessionState As String, ByVal SessionUser As String, ByVal SessionName As String) As Session - Dim newSes As New Session + Public Overloads Function Add(ByVal sessionId As Long, ByVal sessionState As String, ByVal sessionUser As String, ByVal sessionName As String) As Session + Dim newSession As New Session Try - With newSes - .SessionID = SessionID - .SessionState = SessionState - .SessionUser = SessionUser - .SessionName = SessionName + With newSession + .SessionId = sessionId + .SessionState = sessionState + .SessionUser = sessionUser + .SessionName = sessionName End With - List.Add(newSes) + List.Add(newSession) Catch ex As Exception - MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, My.Language.strRdpAddSessionFailed & vbNewLine & ex.Message, True) + MessageCollector.AddExceptionMessage(My.Language.strRdpAddSessionFailed, ex, MessageClass.ErrorMsg, True) End Try - Return newSes + Return newSession End Function Public Sub ClearSessions() @@ -742,45 +756,10 @@ Namespace Connection Public Class Session Inherits CollectionBase - Private lngSessionID As Long - Public Property SessionID() As Long - Get - Return lngSessionID - End Get - Set(ByVal Value As Long) - lngSessionID = Value - End Set - End Property - - Private lngSessionState As String + Public Property SessionId() As Long Public Property SessionState() As String - Get - Return lngSessionState - End Get - Set(ByVal Value As String) - lngSessionState = Value - End Set - End Property - - Private strSessionUser As String Public Property SessionUser() As String - Get - Return strSessionUser - End Get - Set(ByVal Value As String) - strSessionUser = Value - End Set - End Property - - Private strSessionName As String Public Property SessionName() As String - Get - Return strSessionName - End Get - Set(ByVal Value As String) - strSessionName = Value - End Set - End Property End Class #End Region diff --git a/mRemoteV1/UI/UI.Window.Sessions.vb b/mRemoteV1/UI/UI.Window.Sessions.vb index f6e0ae336..fa7e68116 100644 --- a/mRemoteV1/UI/UI.Window.Sessions.vb +++ b/mRemoteV1/UI/UI.Window.Sessions.vb @@ -129,10 +129,10 @@ Namespace UI With data impersonator.StartImpersonation(.Domain, .Username, .Password) - If Not terminalSessions.OpenConnection(.Hostname) Then Return - serverHandle = terminalSessions.ServerHandle + serverHandle = terminalSessions.OpenConnection(.Hostname) + If serverHandle = 0 Then Return - GetSessions(terminalSessions) + GetSessions(terminalSessions, serverHandle) End With _retrieved = True @@ -149,11 +149,11 @@ Namespace UI End Sub ' Get sessions from an already impersonated and connected TerminalSessions object - Private Sub GetSessions(ByVal terminalSessions As mRemoteNG.Connection.Protocol.RDP.TerminalSessions) - Dim rdpSessions As mRemoteNG.Connection.Protocol.RDP.Sessions = terminalSessions.GetSessions + Private Sub GetSessions(ByVal terminalSessions As mRemoteNG.Connection.Protocol.RDP.TerminalSessions, ByVal serverHandle As Long) + Dim rdpSessions As mRemoteNG.Connection.Protocol.RDP.SessionsCollection = terminalSessions.GetSessions(serverHandle) For Each session As mRemoteNG.Connection.Protocol.RDP.Session In rdpSessions Dim item As New ListViewItem - item.Tag = session.SessionID + item.Tag = session.SessionId item.Text = session.SessionUser item.SubItems.Add(session.SessionState) item.SubItems.Add(Replace(session.SessionName, vbNewLine, "")) @@ -174,13 +174,13 @@ Namespace UI impersonator.StartImpersonation(.Domain, .Username, .Password) - If terminalSessions.OpenConnection(.Hostname) Then - serverHandle = terminalSessions.ServerHandle - terminalSessions.KillSession(.SessionId) + serverHandle = terminalSessions.OpenConnection(.Hostname) + If Not serverHandle = 0 Then + terminalSessions.KillSession(serverHandle, .SessionId) End If ClearList() - GetSessions(terminalSessions) + GetSessions(terminalSessions, serverHandle) _retrieved = True End With From 0a82828d2e8a9e2d26568b2cdd4647fabec31d25 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Fri, 25 Oct 2013 00:57:21 -0500 Subject: [PATCH 11/18] Fix log file not showing operating system version on Windows XP and Windows Server 2003. --- CHANGELOG.TXT | 3 ++- mRemoteV1/App/App.Runtime.vb | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 1c8654a72..83ce2428b 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,11 +1,12 @@ 1.71 (XXXX-XX-XX): Fixed issue MR-574 - Crash when retrieving RDP session list if eolwtscom.dll is not registered + Fixed log file not showing operating system version on Windows XP and Windows Server 2003. 1.71 Release Candidate 2 (2013-10-16): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' Fixed issue MR-565 - Double Folder keep heritage on the initial Folder Fixed issue MR-566 - Typo in German UI Automatic Update Settings - Fixed duplicated folders possibly being named "New Connection" instead of the original folder's name + Fixed duplicated folders possibly being named "New Connection" instead of the original folder's name. 1.71 Release Candidate 1 (2013-10-01): Fixed issue MR-495 - Having a negative range in port scan creates memory exhaustion. diff --git a/mRemoteV1/App/App.Runtime.vb b/mRemoteV1/App/App.Runtime.vb index 84687f285..d6f983e32 100644 --- a/mRemoteV1/App/App.Runtime.vb +++ b/mRemoteV1/App/App.Runtime.vb @@ -503,20 +503,30 @@ Namespace App #End If Log.InfoFormat("Command Line: {0}", Environment.GetCommandLineArgs) + Dim osVersion As String = String.Empty + Dim servicePack As String = String.Empty Try - Dim servicePack As Integer - For Each managementObject As ManagementObject In New ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem").Get() - servicePack = managementObject.GetPropertyValue("ServicePackMajorVersion") - If servicePack = 0 Then - Log.InfoFormat("{0} {1}", managementObject.GetPropertyValue("Caption").Trim, managementObject.GetPropertyValue("OSArchitecture")) - Else - Log.InfoFormat("{0} Service Pack {1} {2}", managementObject.GetPropertyValue("Caption").Trim, servicePack.ToString, managementObject.GetPropertyValue("OSArchitecture")) - End If + For Each managementObject As ManagementObject In New ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True").Get() + osVersion = managementObject.GetPropertyValue("Caption").Trim() + Dim servicePackNumber As Integer = managementObject.GetPropertyValue("ServicePackMajorVersion") + If Not servicePackNumber = 0 Then servicePack = String.Format("Service Pack {0}", servicePackNumber) Next Catch ex As Exception Log.WarnFormat("Error retrieving operating system information from WMI. {0}", ex.Message) End Try + Dim architecture As String = String.Empty + Try + For Each managementObject As ManagementObject In New ManagementObjectSearcher("SELECT * FROM Win32_Processor WHERE DeviceID='CPU0'").Get() + Dim addressWidth As Integer = managementObject.GetPropertyValue("AddressWidth") + architecture = String.Format("{0}-bit", addressWidth) + Next + Catch ex As Exception + Log.WarnFormat("Error retrieving operating system address width from WMI. {0}", ex.Message) + End Try + + Log.InfoFormat(String.Join(" ", Array.FindAll(New String() {osVersion, servicePack, architecture}, Function(s) Not String.IsNullOrEmpty(s)))) + Log.InfoFormat("Microsoft .NET CLR {0}", Version.ToString) Log.InfoFormat("System Culture: {0}/{1}", Thread.CurrentThread.CurrentUICulture.Name, Thread.CurrentThread.CurrentUICulture.NativeName) End If From 8c3f4c06dfa5b0a6f9196d7ad7084747d4efbc2e Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Sun, 27 Oct 2013 01:40:32 -0500 Subject: [PATCH 12/18] Add feature MR-547 - Add support for Xming Portable PuTTY --- CHANGELOG.TXT | 1 + mRemoteV1/App/App.Runtime.vb | 7 +- mRemoteV1/Config/Config.Connections.Load.vb | 2 +- .../Config/Putty/DefaultSettingsProvider.vb | 21 ++ mRemoteV1/Config/Putty/Provider.vb | 91 +++++++ mRemoteV1/Config/Putty/RegistryProvider.vb | 112 ++++++++ mRemoteV1/Config/Putty/Sessions.vb | 161 +++++++++++ mRemoteV1/Config/Putty/XmingProvider.vb | 202 ++++++++++++++ mRemoteV1/Config/PuttySessions.vb | 250 ------------------ mRemoteV1/Connection/Connection.Info.vb | 3 +- .../Connection.Protocol.PuttyBase.vb | 14 +- mRemoteV1/Forms/frmMain.vb | 2 +- mRemoteV1/Forms/frmOptions.vb | 22 +- mRemoteV1/Root/PuttySessions.Info.vb | 18 +- mRemoteV1/Tools/PuttyTypeDetector.vb | 70 +++++ mRemoteV1/UI/UI.Window.Config.vb | 11 +- mRemoteV1/UI/UI.Window.Tree.vb | 2 +- mRemoteV1/mRemoteV1.vbproj | 7 +- 18 files changed, 708 insertions(+), 288 deletions(-) create mode 100644 mRemoteV1/Config/Putty/DefaultSettingsProvider.vb create mode 100644 mRemoteV1/Config/Putty/Provider.vb create mode 100644 mRemoteV1/Config/Putty/RegistryProvider.vb create mode 100644 mRemoteV1/Config/Putty/Sessions.vb create mode 100644 mRemoteV1/Config/Putty/XmingProvider.vb delete mode 100644 mRemoteV1/Config/PuttySessions.vb create mode 100644 mRemoteV1/Tools/PuttyTypeDetector.vb diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index ecf7116a6..3729beaf2 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,5 +1,6 @@ 1.72: Added feature MR-141 - Add a default protocol option + Added feature MR-547 - Add support for Xming Portable PuTTY Made improvement MR-367 - Make the 'Connect' button on the 'Quick Connect' toolbar a forced dropdown Fixed misleading log messages about RD Gateway support. Removed invalid "Site" configuration option from PuTTY Saved Sessions diff --git a/mRemoteV1/App/App.Runtime.vb b/mRemoteV1/App/App.Runtime.vb index 690be8148..107df639c 100644 --- a/mRemoteV1/App/App.Runtime.vb +++ b/mRemoteV1/App/App.Runtime.vb @@ -5,6 +5,7 @@ Imports mRemoteNG.Messages Imports mRemoteNG.Connection Imports mRemoteNG.Tools Imports PSTaskDialog +Imports mRemoteNG.Config.Putty Imports WeifenLuo.WinFormsUI.Docking Imports System.IO Imports Crownwood @@ -370,13 +371,13 @@ Namespace App Dim isFipsPolicyEnabled As Boolean = False ' Windows XP/Windows Server 2003 - regKey = Registry.LocalMachine.OpenSubKey("System\CurrentControlSet\Control\Lsa") + regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System\CurrentControlSet\Control\Lsa") If regKey IsNot Nothing Then If Not regKey.GetValue("FIPSAlgorithmPolicy") = 0 Then isFipsPolicyEnabled = True End If ' Windows Vista/Windows Server 2008 and newer - regKey = Registry.LocalMachine.OpenSubKey("System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy") + regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy") If regKey IsNot Nothing Then If Not regKey.GetValue("Enabled") = 0 Then isFipsPolicyEnabled = True End If @@ -703,7 +704,7 @@ Namespace App Public Shared Sub Cleanup() Try - PuttySessions.StopWatcher() + Putty.Sessions.StopWatcher() If NotificationAreaIcon IsNot Nothing Then If NotificationAreaIcon.Disposed = False Then diff --git a/mRemoteV1/Config/Config.Connections.Load.vb b/mRemoteV1/Config/Config.Connections.Load.vb index 9b532ded7..e3462bb7b 100644 --- a/mRemoteV1/Config/Config.Connections.Load.vb +++ b/mRemoteV1/Config/Config.Connections.Load.vb @@ -166,7 +166,7 @@ Namespace Config If import = False Then SetMainFormText(ConnectionFileName) - PuttySessions.AddSessionsToTree() + Putty.Sessions.AddSessionsToTree() End If End Sub #End Region diff --git a/mRemoteV1/Config/Putty/DefaultSettingsProvider.vb b/mRemoteV1/Config/Putty/DefaultSettingsProvider.vb new file mode 100644 index 000000000..d7c9d5e07 --- /dev/null +++ b/mRemoteV1/Config/Putty/DefaultSettingsProvider.vb @@ -0,0 +1,21 @@ +Imports mRemoteNG.Connection.PuttySession + +Namespace Config.Putty + Public Class DefaultSettingsProvider + Inherits Provider + + Public Overrides Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() + Dim sessionNames(0) As String + If raw Then + sessionNames(0) = "Default%20Settings" + Else + sessionNames(0) = "Default Settings" + End If + Return sessionNames + End Function + + Public Overrides Function GetSession(ByVal sessionName As String) As Info + Return Nothing + End Function + End Class +End Namespace diff --git a/mRemoteV1/Config/Putty/Provider.vb b/mRemoteV1/Config/Putty/Provider.vb new file mode 100644 index 000000000..ae0816da2 --- /dev/null +++ b/mRemoteV1/Config/Putty/Provider.vb @@ -0,0 +1,91 @@ +Imports mRemoteNG.My + +Namespace Config.Putty + Public MustInherit Class Provider + Private _rootTreeNode As TreeNode + Public ReadOnly Property RootTreeNode As TreeNode + Get + If _rootTreeNode Is Nothing Then _rootTreeNode = CreateRootTreeNode() + Return _rootTreeNode + End Get + End Property + + Private Delegate Function CreateRootTreeNodeDelegate() As TreeNode + Protected Overridable Function CreateRootTreeNode() As TreeNode + Dim treeView As TreeView = Tree.Node.TreeView + If treeView Is Nothing Then Return Nothing + If treeView.InvokeRequired Then + Return treeView.Invoke(New CreateRootTreeNodeDelegate(AddressOf CreateRootTreeNode)) + End If + + Dim newTreeNode As New TreeNode + RootInfo.TreeNode = newTreeNode + + newTreeNode.Name = _rootInfo.Name + newTreeNode.Text = _rootInfo.Name + newTreeNode.Tag = _rootInfo + newTreeNode.ImageIndex = Images.Enums.TreeImage.PuttySessions + newTreeNode.SelectedImageIndex = Images.Enums.TreeImage.PuttySessions + + Return newTreeNode + End Function + + Private _rootInfo As Root.PuttySessions.Info + Public ReadOnly Property RootInfo() As Root.PuttySessions.Info + Get + If _rootInfo Is Nothing Then _rootInfo = CreateRootInfo() + Return _rootInfo + End Get + End Property + + Protected Overridable Function CreateRootInfo() As Root.PuttySessions.Info + Dim newRootInfo As New Root.PuttySessions.Info + + If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsName) Then + newRootInfo.Name = Language.strPuttySavedSessionsRootName + Else + newRootInfo.Name = My.Settings.PuttySavedSessionsName + End If + + If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsPanel) Then + newRootInfo.Panel = Language.strGeneral + Else + newRootInfo.Panel = My.Settings.PuttySavedSessionsPanel + End If + + Return newRootInfo + End Function + + Public MustOverride Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() + Public MustOverride Function GetSession(ByVal sessionName As String) As Connection.PuttySession.Info + + Public Overridable Function GetSessions() As Connection.PuttySession.Info() + Dim sessionList As New List(Of Connection.PuttySession.Info) + Dim sessionInfo As Connection.Info + For Each sessionName As String In GetSessionNames(True) + sessionInfo = GetSession(sessionName) + If sessionInfo Is Nothing OrElse String.IsNullOrEmpty(sessionInfo.Hostname) Then Continue For + sessionList.Add(sessionInfo) + Next + Return sessionList.ToArray() + End Function + + Public Overridable Sub StartWatcher() + + End Sub + + Public Overridable Sub StopWatcher() + + End Sub + + Public Event SessionChanged(ByVal sender As Object, ByVal e As SessionChangedEventArgs) + + Protected Overridable Sub OnSessionChanged(ByVal e As SessionChangedEventArgs) + RaiseEvent SessionChanged(Me, New SessionChangedEventArgs()) + End Sub + + Public Class SessionChangedEventArgs + Inherits EventArgs + End Class + End Class +End Namespace diff --git a/mRemoteV1/Config/Putty/RegistryProvider.vb b/mRemoteV1/Config/Putty/RegistryProvider.vb new file mode 100644 index 000000000..3c6940366 --- /dev/null +++ b/mRemoteV1/Config/Putty/RegistryProvider.vb @@ -0,0 +1,112 @@ +Imports System.Management +Imports mRemoteNG.App +Imports mRemoteNG.Messages +Imports Microsoft.Win32 +Imports mRemoteNG.Connection.Protocol +Imports System.Security.Principal + +Namespace Config.Putty + Public Class RegistryProvider + Inherits Provider + + Private Const PuttySessionsKey As String = "Software\SimonTatham\PuTTY\Sessions" + Private Shared _eventWatcher As ManagementEventWatcher + + Public Overrides Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() + Dim sessionsKey As RegistryKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey) + If sessionsKey Is Nothing Then Return New String() {} + + Dim sessionNames As New List(Of String) + For Each sessionName As String In sessionsKey.GetSubKeyNames() + If raw Then + sessionNames.Add(sessionName) + Else + sessionNames.Add(Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B"))) + End If + Next + + If sessionNames.Contains("Default%20Settings") Then ' Do not localize + sessionNames.Remove("Default%20Settings") + End If + If sessionNames.Contains("Default Settings") Then + sessionNames.Remove("Default Settings") + End If + + Return sessionNames.ToArray() + End Function + + Public Overrides Function GetSession(ByVal sessionName As String) As Connection.PuttySession.Info + Dim sessionsKey As RegistryKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey) + If sessionsKey Is Nothing Then Return Nothing + + Dim sessionKey As RegistryKey = sessionsKey.OpenSubKey(sessionName) + If sessionKey Is Nothing Then Return Nothing + + sessionName = Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B")) + + Dim sessionInfo As New Connection.PuttySession.Info + With sessionInfo + .PuttySession = sessionName + .Name = sessionName + .Hostname = sessionKey.GetValue("HostName") + .Username = sessionKey.GetValue("UserName") + Dim protocol As String = sessionKey.GetValue("Protocol") + If protocol Is Nothing Then protocol = "ssh" + Select Case protocol.ToLowerInvariant() + Case "raw" + .Protocol = Protocols.RAW + Case "rlogin" + .Protocol = Protocols.Rlogin + Case "serial" + Return Nothing + Case "ssh" + Dim sshVersionObject As Object = sessionKey.GetValue("SshProt") + If sshVersionObject IsNot Nothing Then + Dim sshVersion As Integer = CType(sshVersionObject, Integer) + If sshVersion >= 2 Then + .Protocol = Protocols.SSH2 + Else + .Protocol = Protocols.SSH1 + End If + Else + .Protocol = Protocols.SSH2 + End If + Case "telnet" + .Protocol = Protocols.Telnet + Case Else + Return Nothing + End Select + .Port = sessionKey.GetValue("PortNumber") + End With + + Return sessionInfo + End Function + + Public Overrides Sub StartWatcher() + If _eventWatcher IsNot Nothing Then Return + + Try + Dim currentUserSid As String = WindowsIdentity.GetCurrent().User.Value + Dim key As String = String.Join("\", {currentUserSid, PuttySessionsKey}).Replace("\", "\\") + Dim query As New WqlEventQuery(String.Format("SELECT * FROM RegistryTreeChangeEvent WHERE Hive = 'HKEY_USERS' AND RootPath = '{0}'", key)) + _eventWatcher = New ManagementEventWatcher(query) + AddHandler _eventWatcher.EventArrived, AddressOf OnManagementEventArrived + _eventWatcher.Start() + Catch ex As Exception + Runtime.MessageCollector.AddExceptionMessage("PuttySessions.Watcher.StartWatching() failed.", ex, MessageClass.WarningMsg, True) + End Try + End Sub + + Public Overrides Sub StopWatcher() + If _eventWatcher Is Nothing Then Return + _eventWatcher.Stop() + _eventWatcher.Dispose() + _eventWatcher = Nothing + End Sub + + Private Sub OnManagementEventArrived(ByVal sender As Object, ByVal e As EventArrivedEventArgs) + OnSessionChanged(New SessionChangedEventArgs()) + End Sub + End Class +End Namespace + diff --git a/mRemoteV1/Config/Putty/Sessions.vb b/mRemoteV1/Config/Putty/Sessions.vb new file mode 100644 index 000000000..8f389442a --- /dev/null +++ b/mRemoteV1/Config/Putty/Sessions.vb @@ -0,0 +1,161 @@ +Imports System.ComponentModel +Imports mRemoteNG.Tools + +Namespace Config.Putty + Public Class Sessions + Private Shared _providers As List(Of Provider) + Private Shared ReadOnly Property Providers() As List(Of Provider) + Get + If _providers Is Nothing OrElse _providers.Count = 0 Then AddProviders() + Return _providers + End Get + End Property + + Private Shared Sub AddProviders() + _providers = New List(Of Provider)() + _providers.Add(New DefaultSettingsProvider()) + _providers.Add(New RegistryProvider()) + _providers.Add(New XmingProvider()) + End Sub + + Private Delegate Sub AddSessionsToTreeDelegate() + Public Shared Sub AddSessionsToTree() + Dim treeView As TreeView = Tree.Node.TreeView + If treeView Is Nothing Then Return + If treeView.InvokeRequired Then + treeView.Invoke(New AddSessionsToTreeDelegate(AddressOf AddSessionsToTree)) + Return + End If + + Dim puttyType As PuttyTypeDetector.PuttyType = PuttyTypeDetector.GetPuttyType() + + For Each provider As Provider In Providers + Dim enabled As Boolean = True + Select Case puttyType + Case PuttyTypeDetector.PuttyType.Xming + If TypeOf (provider) Is RegistryProvider Then enabled = False + Case Else + If TypeOf (provider) Is XmingProvider Then enabled = False + End Select + + Dim rootTreeNode As TreeNode = provider.RootTreeNode + Dim inUpdate As Boolean = False + + Dim savedSessions As New List(Of Connection.Info)(provider.GetSessions()) + If Not enabled Or savedSessions Is Nothing OrElse savedSessions.Count = 0 Then + If rootTreeNode IsNot Nothing AndAlso treeView.Nodes.Contains(rootTreeNode) Then + treeView.BeginUpdate() + treeView.Nodes.Remove(rootTreeNode) + treeView.EndUpdate() + End If + Continue For + End If + + If Not treeView.Nodes.Contains(rootTreeNode) Then + If Not inUpdate Then + treeView.BeginUpdate() + inUpdate = True + End If + treeView.Nodes.Add(rootTreeNode) + End If + + Dim newTreeNodes As New List(Of TreeNode) + For Each sessionInfo As Connection.PuttySession.Info In savedSessions + Dim treeNode As TreeNode + Dim isNewNode As Boolean + If rootTreeNode.Nodes.ContainsKey(sessionInfo.Name) Then + treeNode = rootTreeNode.Nodes.Item(sessionInfo.Name) + isNewNode = False + Else + treeNode = Tree.Node.AddNode(Tree.Node.Type.PuttySession, sessionInfo.Name) + If treeNode Is Nothing Then Continue For + treeNode.Name = treeNode.Text + treeNode.ImageIndex = Images.Enums.TreeImage.ConnectionClosed + treeNode.SelectedImageIndex = Images.Enums.TreeImage.ConnectionClosed + isNewNode = True + End If + + sessionInfo.RootPuttySessionsInfo = provider.RootInfo + sessionInfo.TreeNode = treeNode + sessionInfo.Inherit.TurnOffInheritanceCompletely() + + treeNode.Tag = sessionInfo + + If isNewNode Then newTreeNodes.Add(treeNode) + Next + + For Each treeNode As TreeNode In rootTreeNode.Nodes + If Not savedSessions.Contains(treeNode.Tag) Then + If Not inUpdate Then + treeView.BeginUpdate() + inUpdate = True + End If + rootTreeNode.Nodes.Remove(treeNode) + End If + Next + + If Not newTreeNodes.Count = 0 Then + If Not inUpdate Then + treeView.BeginUpdate() + inUpdate = True + End If + rootTreeNode.Nodes.AddRange(newTreeNodes.ToArray()) + End If + + If inUpdate Then + Tree.Node.Sort(rootTreeNode, SortOrder.Ascending) + rootTreeNode.Expand() + treeView.EndUpdate() + End If + Next + End Sub + + Protected Shared Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() + Dim sessionNames As New List(Of String) + For Each provider As Provider In Providers + sessionNames.AddRange(provider.GetSessionNames()) + Next + Return sessionNames.ToArray() + End Function + + Public Shared Sub StartWatcher() + For Each provider As Provider In Providers + provider.StartWatcher() + AddHandler provider.SessionChanged, AddressOf SessionChanged + Next + End Sub + + Public Shared Sub StopWatcher() + For Each provider As Provider In Providers + provider.StopWatcher() + RemoveHandler provider.SessionChanged, AddressOf SessionChanged + Next + End Sub + + Public Shared Sub SessionChanged(ByVal sender As Object, ByVal e As Provider.SessionChangedEventArgs) + AddSessionsToTree() + End Sub + + Public Class SessionList + Inherits StringConverter + + Public Shared ReadOnly Property Names() As String() + Get + Return GetSessionNames() + End Get + End Property + + Public Overloads Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection + Return New StandardValuesCollection(Names) + End Function + + Public Overloads Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean + Return True + End Function + + Public Overloads Overrides Function GetStandardValuesSupported(ByVal context As ITypeDescriptorContext) As Boolean + Return True + End Function + End Class + End Class +End Namespace diff --git a/mRemoteV1/Config/Putty/XmingProvider.vb b/mRemoteV1/Config/Putty/XmingProvider.vb new file mode 100644 index 000000000..84fbb2629 --- /dev/null +++ b/mRemoteV1/Config/Putty/XmingProvider.vb @@ -0,0 +1,202 @@ +Imports System.IO +Imports mRemoteNG.App +Imports mRemoteNG.Messages +Imports mRemoteNG.Connection.Protocol + +Namespace Config.Putty + Public Class XmingProvider + Inherits Provider + + Private Shared _eventWatcher As FileSystemWatcher + + Private Shared Function GetPuttyConfPath() As String + Dim puttyPath As String + If My.Settings.UseCustomPuttyPath Then + puttyPath = My.Settings.CustomPuttyPath + Else + puttyPath = Info.General.PuttyPath + End If + Return Path.Combine(Path.GetDirectoryName(puttyPath), "putty.conf") + End Function + + Private Shared Function GetSessionsFolderPath() As String + Dim puttyConfPath As String = GetPuttyConfPath() + Dim sessionFileReader As New PuttyConfFileReader(puttyConfPath) + Dim basePath As String = Environment.ExpandEnvironmentVariables(sessionFileReader.GetValue("sshk&sess")) + Return Path.Combine(basePath, "sessions") + End Function + + Public Overrides Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() + Dim sessionsFolderPath As String = GetSessionsFolderPath() + If Not Directory.Exists(sessionsFolderPath) Then Return New String() {} + + Dim sessionNames As New List(Of String) + For Each sessionName As String In Directory.GetFiles(sessionsFolderPath) + sessionName = Path.GetFileName(sessionName) + If raw Then + sessionNames.Add(sessionName) + Else + sessionNames.Add(Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B"))) + End If + Next + + If sessionNames.Contains("Default%20Settings") Then ' Do not localize + sessionNames.Remove("Default%20Settings") + End If + If sessionNames.Contains("Default Settings") Then + sessionNames.Remove("Default Settings") + End If + + Return sessionNames.ToArray() + End Function + + Public Overrides Function GetSession(ByVal sessionName As String) As Connection.PuttySession.Info + Dim sessionsFolderPath As String = GetSessionsFolderPath() + If Not Directory.Exists(sessionsFolderPath) Then Return Nothing + + Dim sessionFile As String = Path.Combine(sessionsFolderPath, sessionName) + If Not File.Exists(sessionFile) Then Return Nothing + + sessionName = Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B")) + + Dim sessionFileReader As New SessionFileReader(sessionFile) + Dim sessionInfo As New Connection.PuttySession.Info + With sessionInfo + .PuttySession = sessionName + .Name = sessionName + .Hostname = sessionFileReader.GetValue("HostName") + .Username = sessionFileReader.GetValue("UserName") + Dim protocol As String = sessionFileReader.GetValue("Protocol") + If protocol Is Nothing Then protocol = "ssh" + Select Case protocol.ToLowerInvariant() + Case "raw" + .Protocol = Protocols.RAW + Case "rlogin" + .Protocol = Protocols.Rlogin + Case "serial" + Return Nothing + Case "ssh" + Dim sshVersionObject As Object = sessionFileReader.GetValue("SshProt") + If sshVersionObject IsNot Nothing Then + Dim sshVersion As Integer = CType(sshVersionObject, Integer) + If sshVersion >= 2 Then + .Protocol = Protocols.SSH2 + Else + .Protocol = Protocols.SSH1 + End If + Else + .Protocol = Protocols.SSH2 + End If + Case "telnet" + .Protocol = Protocols.Telnet + Case Else + Return Nothing + End Select + .Port = sessionFileReader.GetValue("PortNumber") + End With + + Return sessionInfo + End Function + + Public Overrides Sub StartWatcher() + If _eventWatcher IsNot Nothing Then Return + + Try + _eventWatcher = New FileSystemWatcher(GetSessionsFolderPath()) + _eventWatcher.NotifyFilter = (NotifyFilters.FileName Or NotifyFilters.LastWrite) + AddHandler _eventWatcher.Changed, AddressOf OnFileSystemEventArrived + AddHandler _eventWatcher.Created, AddressOf OnFileSystemEventArrived + AddHandler _eventWatcher.Deleted, AddressOf OnFileSystemEventArrived + AddHandler _eventWatcher.Renamed, AddressOf OnFileSystemEventArrived + _eventWatcher.EnableRaisingEvents = True + Catch ex As Exception + Runtime.MessageCollector.AddExceptionMessage("XmingPortablePuttySessions.Watcher.StartWatching() failed.", ex, MessageClass.WarningMsg, True) + End Try + End Sub + + Public Overrides Sub StopWatcher() + If _eventWatcher Is Nothing Then Return + _eventWatcher.EnableRaisingEvents = False + _eventWatcher.Dispose() + _eventWatcher = Nothing + End Sub + + Private Sub OnFileSystemEventArrived(ByVal sender As Object, ByVal e As FileSystemEventArgs) + OnSessionChanged(New SessionChangedEventArgs()) + End Sub + + Private Class PuttyConfFileReader + Public Sub New(ByVal puttyConfFile As String) + _puttyConfFile = puttyConfFile + End Sub + + Private ReadOnly _puttyConfFile As String + Private _configurationLoaded As Boolean = False + Private ReadOnly _configuration As New Dictionary(Of String, String) + + Private Sub LoadConfiguration() + _configurationLoaded = True + Try + If Not File.Exists(_puttyConfFile) Then Return + Using streamReader As New StreamReader(_puttyConfFile) + Dim line As String + Do + line = streamReader.ReadLine() + If line Is Nothing Then Exit Do + line = line.Trim() + If line = String.Empty Then Continue Do ' Blank line + If line.Substring(0, 1) = ";" Then Continue Do ' Comment + Dim parts() As String = line.Split(New Char() {"="}, 2) + If parts.Length < 2 Then Continue Do + If _configuration.ContainsKey(parts(0)) Then Continue Do ' As per http://www.straightrunning.com/XmingNotes/portableputty.php only first entry is used + _configuration.Add(parts(0), parts(1)) + Loop + End Using + Catch ex As Exception + Runtime.MessageCollector.AddExceptionMessage("PuttyConfFileReader.LoadConfiguration() failed.", ex, MessageClass.ErrorMsg, True) + End Try + End Sub + + Public Function GetValue(ByVal setting As String) As String + If Not _configurationLoaded Then LoadConfiguration() + If Not _configuration.ContainsKey(setting) Then Return String.Empty + Return _configuration(setting) + End Function + End Class + + Private Class SessionFileReader + Public Sub New(ByVal sessionFile As String) + _sessionFile = sessionFile + End Sub + + Private ReadOnly _sessionFile As String + Private _sessionInfoLoaded As Boolean = False + Private ReadOnly _sessionInfo As New Dictionary(Of String, String) + + Private Sub LoadSessionInfo() + _sessionInfoLoaded = True + Try + If Not File.Exists(_sessionFile) Then Return + Using streamReader As New StreamReader(_sessionFile) + Dim line As String + Do + line = streamReader.ReadLine() + If line Is Nothing Then Exit Do + Dim parts() As String = line.Split(New Char() {"\"}) + If parts.Length < 2 Then Continue Do + _sessionInfo.Add(parts(0), parts(1)) + Loop + End Using + Catch ex As Exception + Runtime.MessageCollector.AddExceptionMessage("SessionFileReader.LoadSessionInfo() failed.", ex, MessageClass.ErrorMsg, True) + End Try + End Sub + + Public Function GetValue(ByVal setting As String) As String + If Not _sessionInfoLoaded Then LoadSessionInfo() + If Not _sessionInfo.ContainsKey(setting) Then Return String.Empty + Return _sessionInfo(setting) + End Function + End Class + End Class +End Namespace diff --git a/mRemoteV1/Config/PuttySessions.vb b/mRemoteV1/Config/PuttySessions.vb deleted file mode 100644 index d0248912b..000000000 --- a/mRemoteV1/Config/PuttySessions.vb +++ /dev/null @@ -1,250 +0,0 @@ -Imports System.ComponentModel -Imports System.Management -Imports mRemoteNG.Messages -Imports Microsoft.Win32 -Imports mRemoteNG.Connection.Protocol -Imports mRemoteNG.My -Imports mRemoteNG.App.Runtime -Imports System.Security.Principal - -Namespace Config - Public Class PuttySessions - Private Const PuttySessionsKey As String = "Software\SimonTatham\PuTTY\Sessions" - Private Shared _rootTreeNode As TreeNode - Private Shared _eventWatcher As ManagementEventWatcher - - Private Delegate Sub AddSessionsToTreeDelegate() - Public Shared Sub AddSessionsToTree() - Dim treeView As TreeView = Tree.Node.TreeView - If treeView Is Nothing Then Return - If treeView.InvokeRequired Then - treeView.Invoke(New AddSessionsToTreeDelegate(AddressOf AddSessionsToTree)) - Return - End If - - Dim savedSessions As New List(Of Connection.Info)(LoadSessions()) - If savedSessions Is Nothing Or savedSessions.Count = 0 Then - If _rootTreeNode IsNot Nothing AndAlso treeView.Nodes.Contains(_rootTreeNode) Then - treeView.BeginUpdate() - treeView.Nodes.Remove(_rootTreeNode) - treeView.EndUpdate() - End If - Return - End If - - Dim puttyRootInfo As New Root.PuttySessions.Info() - If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsName) Then - puttyRootInfo.Name = Language.strPuttySavedSessionsRootName - Else - puttyRootInfo.Name = My.Settings.PuttySavedSessionsName - End If - If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsPanel) Then - puttyRootInfo.Panel = Language.strGeneral - Else - puttyRootInfo.Panel = My.Settings.PuttySavedSessionsPanel - End If - - Dim inUpdate As Boolean = False - - If _rootTreeNode Is Nothing Then - _rootTreeNode = New TreeNode - _rootTreeNode.Name = puttyRootInfo.Name - _rootTreeNode.Text = puttyRootInfo.Name - _rootTreeNode.Tag = puttyRootInfo - _rootTreeNode.ImageIndex = Images.Enums.TreeImage.PuttySessions - _rootTreeNode.SelectedImageIndex = Images.Enums.TreeImage.PuttySessions - End If - - If Not treeView.Nodes.Contains(_rootTreeNode) Then - If Not inUpdate Then - treeView.BeginUpdate() - inUpdate = True - End If - treeView.Nodes.Add(_rootTreeNode) - End If - - puttyRootInfo.TreeNode = _rootTreeNode - - Dim newTreeNodes As New List(Of TreeNode) - For Each sessionInfo As Connection.PuttySession.Info In savedSessions - Dim treeNode As TreeNode - Dim isNewNode As Boolean - If _rootTreeNode.Nodes.ContainsKey(sessionInfo.Name) Then - treeNode = _rootTreeNode.Nodes.Item(sessionInfo.Name) - isNewNode = False - Else - treeNode = Tree.Node.AddNode(Tree.Node.Type.PuttySession, sessionInfo.Name) - If treeNode Is Nothing Then Continue For - treeNode.Name = treeNode.Text - treeNode.ImageIndex = Images.Enums.TreeImage.ConnectionClosed - treeNode.SelectedImageIndex = Images.Enums.TreeImage.ConnectionClosed - isNewNode = True - End If - - sessionInfo.RootPuttySessionsInfo = puttyRootInfo - sessionInfo.TreeNode = treeNode - sessionInfo.Inherit.TurnOffInheritanceCompletely() - - treeNode.Tag = sessionInfo - - If isNewNode Then newTreeNodes.Add(treeNode) - Next - - For Each treeNode As TreeNode In _rootTreeNode.Nodes - If Not savedSessions.Contains(treeNode.Tag) Then - If Not inUpdate Then - treeView.BeginUpdate() - inUpdate = True - End If - _rootTreeNode.Nodes.Remove(treeNode) - End If - Next - - If Not newTreeNodes.Count = 0 Then - If Not inUpdate Then - treeView.BeginUpdate() - inUpdate = True - End If - _rootTreeNode.Nodes.AddRange(newTreeNodes.ToArray()) - End If - - If inUpdate Then - Tree.Node.Sort(_rootTreeNode, SortOrder.Ascending) - _rootTreeNode.Expand() - treeView.EndUpdate() - End If - End Sub - - Protected Shared Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() - Dim sessionsKey As RegistryKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey) - If sessionsKey Is Nothing Then Return New String() {} - - Dim sessionNames As New List(Of String) - For Each sessionName As String In sessionsKey.GetSubKeyNames() - If raw Then - sessionNames.Add(sessionName) - Else - sessionNames.Add(Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B"))) - End If - Next - - If raw Then - If Not sessionNames.Contains("Default%20Settings") Then ' Do not localize - sessionNames.Insert(0, "Default%20Settings") - End If - Else - If Not sessionNames.Contains("Default Settings") Then - sessionNames.Insert(0, "Default Settings") - End If - End If - - Return sessionNames.ToArray() - End Function - - Protected Shared Function LoadSessions() As Connection.PuttySession.Info() - Dim sessionList As New List(Of Connection.PuttySession.Info) - Dim sessionInfo As Connection.Info - For Each sessionName As String In GetSessionNames(True) - sessionInfo = SessionToConnectionInfo(sessionName) - If sessionInfo Is Nothing OrElse String.IsNullOrEmpty(sessionInfo.Hostname) Then Continue For - sessionList.Add(sessionInfo) - Next - Return sessionList.ToArray() - End Function - - Protected Shared Function SessionToConnectionInfo(ByVal sessionName As String) As Connection.PuttySession.Info - Dim sessionsKey As RegistryKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey) - If sessionsKey Is Nothing Then Return Nothing - - Dim sessionKey As RegistryKey = sessionsKey.OpenSubKey(sessionName) - If sessionKey Is Nothing Then Return Nothing - - sessionName = Web.HttpUtility.UrlDecode(sessionName.Replace("+", "%2B")) - - Dim sessionInfo As New Connection.PuttySession.Info - With sessionInfo - .PuttySession = sessionName - .Name = sessionName - .Hostname = sessionKey.GetValue("HostName") - .Username = sessionKey.GetValue("UserName") - Dim protocol As String = sessionKey.GetValue("Protocol") - If protocol Is Nothing Then protocol = "ssh" - Select Case protocol.ToLowerInvariant() - Case "raw" - .Protocol = Protocols.RAW - Case "rlogin" - .Protocol = Protocols.Rlogin - Case "serial" - Return Nothing - Case "ssh" - Dim sshVersionObject As Object = sessionKey.GetValue("SshProt") - If sshVersionObject IsNot Nothing Then - Dim sshVersion As Integer = CType(sshVersionObject, Integer) - If sshVersion >= 2 Then - .Protocol = Protocols.SSH2 - Else - .Protocol = Protocols.SSH1 - End If - Else - .Protocol = Protocols.SSH2 - End If - Case "telnet" - .Protocol = Protocols.Telnet - Case Else - Return Nothing - End Select - .Port = sessionKey.GetValue("PortNumber") - End With - - Return sessionInfo - End Function - - Public Shared Sub StartWatcher() - If _eventWatcher IsNot Nothing Then Return - - Try - Dim currentUserSid As String = WindowsIdentity.GetCurrent().User.Value - Dim key As String = String.Join("\", {currentUserSid, PuttySessionsKey}).Replace("\", "\\") - Dim query As New WqlEventQuery(String.Format("SELECT * FROM RegistryTreeChangeEvent WHERE Hive = 'HKEY_USERS' AND RootPath = '{0}'", key)) - _eventWatcher = New ManagementEventWatcher(query) - AddHandler _eventWatcher.EventArrived, AddressOf OnManagementEventArrived - _eventWatcher.Start() - Catch ex As Exception - MessageCollector.AddExceptionMessage("PuttySessions.Watcher.StartWatching() failed.", ex, MessageClass.WarningMsg, True) - End Try - End Sub - - Public Shared Sub StopWatcher() - If _eventWatcher Is Nothing Then Return - _eventWatcher.Stop() - _eventWatcher.Dispose() - _eventWatcher = Nothing - End Sub - - Private Shared Sub OnManagementEventArrived(ByVal sender As Object, ByVal e As EventArrivedEventArgs) - AddSessionsToTree() - End Sub - - Public Class SessionList - Inherits StringConverter - - Public Shared ReadOnly Property Names() As String() - Get - Return GetSessionNames() - End Get - End Property - - Public Overloads Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection - Return New StandardValuesCollection(Names) - End Function - - Public Overloads Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean - Return True - End Function - - Public Overloads Overrides Function GetStandardValuesSupported(ByVal context As ITypeDescriptorContext) As Boolean - Return True - End Function - End Class - End Class -End Namespace diff --git a/mRemoteV1/Connection/Connection.Info.vb b/mRemoteV1/Connection/Connection.Info.vb index 3421459b6..e05800853 100644 --- a/mRemoteV1/Connection/Connection.Info.vb +++ b/mRemoteV1/Connection/Connection.Info.vb @@ -2,6 +2,7 @@ Imports System.Windows.Forms Imports System.ComponentModel Imports mRemoteNG.Tools.LocalizedAttributes Imports mRemoteNG.App.Runtime +Imports mRemoteNG.Config Namespace Connection _ @@ -282,7 +283,7 @@ Namespace Connection Browsable(True), _ LocalizedDisplayName("strPropertyNamePuttySession"), _ LocalizedDescription("strPropertyDescriptionPuttySession"), _ - TypeConverter(GetType(Config.PuttySessions.SessionList))> _ + TypeConverter(GetType(Putty.Sessions.SessionList))> _ Public Overridable Property PuttySession() As String Get If Me._Inherit.PuttySession And Me._Parent IsNot Nothing Then diff --git a/mRemoteV1/Connection/Connection.Protocol.PuttyBase.vb b/mRemoteV1/Connection/Connection.Protocol.PuttyBase.vb index 10160b4e5..7b253415a 100644 --- a/mRemoteV1/Connection/Connection.Protocol.PuttyBase.vb +++ b/mRemoteV1/Connection/Connection.Protocol.PuttyBase.vb @@ -97,7 +97,7 @@ Namespace Connection Public Overrides Function Connect() As Boolean Try - _isPuttyNg = IsFilePuttyNg(PuttyPath) + _isPuttyNg = (PuttyTypeDetector.GetPuttyType() = PuttyTypeDetector.PuttyType.PuttyNg) PuttyProcess = New Process With PuttyProcess.StartInfo @@ -237,18 +237,6 @@ Namespace Connection End Sub #End Region -#Region "Public Shared Methods" - Public Shared Function IsFilePuttyNg(file As String) As Boolean - Dim isPuttyNg As Boolean - Try - isPuttyNg = FileVersionInfo.GetVersionInfo(file).InternalName.Contains("PuTTYNG") - Catch - isPuttyNg = False - End Try - Return isPuttyNg - End Function -#End Region - #Region "Enums" Public Enum Putty_Protocol ssh = 0 diff --git a/mRemoteV1/Forms/frmMain.vb b/mRemoteV1/Forms/frmMain.vb index 13f50a9cf..245547147 100644 --- a/mRemoteV1/Forms/frmMain.vb +++ b/mRemoteV1/Forms/frmMain.vb @@ -75,7 +75,7 @@ Public Class frmMain Return End If - PuttySessions.StartWatcher() + Putty.Sessions.StartWatcher() If My.Settings.StartupComponentsCheck Then Windows.Show(UI.Window.Type.ComponentsCheck) diff --git a/mRemoteV1/Forms/frmOptions.vb b/mRemoteV1/Forms/frmOptions.vb index 136b16128..1ed2dba35 100644 --- a/mRemoteV1/Forms/frmOptions.vb +++ b/mRemoteV1/Forms/frmOptions.vb @@ -1782,13 +1782,23 @@ Public Class frmOptions My.Settings.AutomaticallyGetSessionInfo = Me.chkAutomaticallyGetSessionInfo.Checked My.Settings.ReconnectOnDisconnect = Me.chkAutomaticReconnect.Checked My.Settings.SingleInstance = Me.chkSingleInstance.Checked - My.Settings.UseCustomPuttyPath = Me.chkUseCustomPuttyPath.Checked - My.Settings.CustomPuttyPath = Me.txtCustomPuttyPath.Text - If Settings.UseCustomPuttyPath Then - Connection.Protocol.PuttyBase.PuttyPath = Settings.CustomPuttyPath - Else - Connection.Protocol.PuttyBase.PuttyPath = App.Info.General.PuttyPath + Dim puttyPathChanged As Boolean = False + If Not Settings.CustomPuttyPath = txtCustomPuttyPath.Text Then + puttyPathChanged = True + Settings.CustomPuttyPath = txtCustomPuttyPath.Text + End If + If Not Settings.UseCustomPuttyPath = chkUseCustomPuttyPath.Checked Then + puttyPathChanged = True + Settings.UseCustomPuttyPath = chkUseCustomPuttyPath.Checked + End If + If puttyPathChanged Then + If Settings.UseCustomPuttyPath Then + Connection.Protocol.PuttyBase.PuttyPath = Settings.CustomPuttyPath + Else + Connection.Protocol.PuttyBase.PuttyPath = App.Info.General.PuttyPath + End If + Config.Putty.Sessions.AddSessionsToTree() End If My.Settings.MaxPuttyWaitTime = Me.numPuttyWaitTime.Value diff --git a/mRemoteV1/Root/PuttySessions.Info.vb b/mRemoteV1/Root/PuttySessions.Info.vb index bfd0b6fe5..26f9687da 100644 --- a/mRemoteV1/Root/PuttySessions.Info.vb +++ b/mRemoteV1/Root/PuttySessions.Info.vb @@ -1,4 +1,5 @@ -Imports mRemoteNG.Tools.LocalizedAttributes +Imports mRemoteNG.My +Imports mRemoteNG.Tools.LocalizedAttributes Namespace Root Namespace PuttySessions @@ -9,7 +10,20 @@ Namespace Root MyBase.New(RootType.PuttySessions) End Sub + Private _name As String Public Overrides Property Name() As String + Get + Return _name + End Get + Set(ByVal value As String) + If _name = value Then Return + _name = value + If TreeNode IsNot Nothing Then + TreeNode.Text = value + End If + Settings.PuttySavedSessionsName = value + End Set + End Property Private _panel As String = My.Language.strGeneral - + + + + + Component @@ -280,6 +284,7 @@ + ReconnectGroup.vb From 4acaefe9c33e6071a287704d85c40402f10dc0eb Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Sun, 27 Oct 2013 01:53:24 -0500 Subject: [PATCH 13/18] Add "Reset" to config panel context menu to allow resetting some config settings to their default value. Fix config panel showing settings from previously loaded connection file after loading a new one. Code cleanup. --- CHANGELOG.TXT | 8 +- mRemoteV1/Config/Config.Connections.Load.vb | 139 ++++++------------ mRemoteV1/Root/PuttySessions.Info.vb | 3 +- mRemoteV1/Root/Root.Info.vb | 142 ++++++------------- mRemoteV1/Tools/Tools.LocalizedAttributes.vb | 17 +++ mRemoteV1/UI/UI.Window.Config.vb | 97 +++++++++---- 6 files changed, 182 insertions(+), 224 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 3729beaf2..3eac04bb6 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -2,9 +2,11 @@ Added feature MR-141 - Add a default protocol option Added feature MR-547 - Add support for Xming Portable PuTTY Made improvement MR-367 - Make the 'Connect' button on the 'Quick Connect' toolbar a forced dropdown - Fixed misleading log messages about RD Gateway support. - Removed invalid "Site" configuration option from PuTTY Saved Sessions - Fixed PuTTY Saved Sessions still showing if all saved sessions are removed + Added "Reset" to config panel context menu to allow resetting some config settings to their default value. + Removed misleading log messages about RD Gateway support. + Removed invalid "Site" configuration option from PuTTY Saved Sessions. + Fixed PuTTY Saved Sessions still showing if all saved sessions are removed. + Fixed config panel showing settings from previously loaded connection file after loading a new one. 1.71 (XXXX-XX-XX): Fixed issue MR-574 - Crash when retrieving RDP session list if eolwtscom.dll is not registered diff --git a/mRemoteV1/Config/Config.Connections.Load.vb b/mRemoteV1/Config/Config.Connections.Load.vb index e3462bb7b..320284ed1 100644 --- a/mRemoteV1/Config/Config.Connections.Load.vb +++ b/mRemoteV1/Config/Config.Connections.Load.vb @@ -19,7 +19,7 @@ Namespace Config Private sqlQuery As SqlCommand Private sqlRd As SqlDataReader - Private selNode As TreeNode + Private _selectedTreeNode As TreeNode #End Region #Region "Public Properties" @@ -103,25 +103,9 @@ Namespace Config End Set End Property - Private _RootTreeNode As TreeNode Public Property RootTreeNode() As TreeNode - Get - Return Me._RootTreeNode - End Get - Set(ByVal value As TreeNode) - Me._RootTreeNode = value - End Set - End Property - Private _ConnectionList As Connection.List Public Property ConnectionList() As Connection.List - Get - Return Me._ConnectionList - End Get - Set(ByVal value As Connection.List) - Me._ConnectionList = value - End Set - End Property Private _ContainerList As Container.List Public Property ContainerList() As Container.List @@ -181,7 +165,7 @@ Namespace Config End If Try - App.Runtime.IsConnectionsFileLoaded = False + IsConnectionsFileLoaded = False If _SQLUsername <> "" Then sqlCon = New SqlConnection("Data Source=" & _SQLHost & ";Initial Catalog=" & _SQLDatabaseName & ";User Id=" & _SQLUsername & ";Password=" & _SQLPassword) @@ -197,7 +181,7 @@ Namespace Config sqlRd.Read() If sqlRd.HasRows = False Then - App.Runtime.SaveConnections() + SaveConnections() sqlQuery = New SqlCommand("SELECT * FROM tblRoot", sqlCon) sqlRd = sqlQuery.ExecuteReader(CommandBehavior.CloseConnection) @@ -212,40 +196,33 @@ Namespace Config Throw New Exception(String.Format("Incompatible database schema (schema version {0}).", confVersion)) End If - Dim rootNode As TreeNode - rootNode = New TreeNode(sqlRd.Item("Name")) + RootTreeNode.Name = sqlRd.Item("Name") - Dim rInfo As New Root.Info(Root.Info.RootType.Connection) - rInfo.Name = rootNode.Text - rInfo.TreeNode = rootNode + Dim rootInfo As New Root.Info(Root.Info.RootType.Connection) + rootInfo.Name = RootTreeNode.Name + rootInfo.TreeNode = RootTreeNode - rootNode.Tag = rInfo - rootNode.ImageIndex = Images.Enums.TreeImage.Root - rootNode.SelectedImageIndex = Images.Enums.TreeImage.Root + RootTreeNode.Tag = rootInfo + RootTreeNode.ImageIndex = Images.Enums.TreeImage.Root + RootTreeNode.SelectedImageIndex = Images.Enums.TreeImage.Root If Security.Crypt.Decrypt(sqlRd.Item("Protected"), pW) <> "ThisIsNotProtected" Then - If Authenticate(sqlRd.Item("Protected"), False, rInfo) = False Then + If Authenticate(sqlRd.Item("Protected"), False, rootInfo) = False Then My.Settings.LoadConsFromCustomLocation = False My.Settings.CustomConsPath = "" - rootNode.Remove() + RootTreeNode.Remove() Exit Sub End If End If - 'Me._RootTreeNode.Text = rootNode.Text - 'Me._RootTreeNode.Tag = rootNode.Tag - 'Me._RootTreeNode.ImageIndex = Images.Enums.TreeImage.Root - 'Me._RootTreeNode.SelectedImageIndex = Images.Enums.TreeImage.Root - sqlRd.Close() Windows.treeForm.tvConnections.BeginUpdate() ' SECTION 3. Populate the TreeView with the DOM nodes. - AddNodesFromSQL(rootNode) - 'AddNodeFromXml(xDom.DocumentElement, Me._RootTreeNode) + AddNodesFromSQL(RootTreeNode) - rootNode.Expand() + RootTreeNode.Expand() 'expand containers For Each contI As Container.Info In Me._ContainerList @@ -258,21 +235,16 @@ Namespace Config 'open connections from last mremote session If My.Settings.OpenConsFromLastSession = True And My.Settings.NoReconnect = False Then - For Each conI As Connection.Info In Me._ConnectionList + For Each conI As Connection.Info In ConnectionList If conI.PleaseConnect = True Then - App.Runtime.OpenConnection(conI) + OpenConnection(conI) End If Next End If - 'Tree.Node.TreeView.Nodes.Clear() - 'Tree.Node.TreeView.Nodes.Add(rootNode) - - AddNodeToTree(rootNode) - SetSelectedNode(selNode) - - App.Runtime.IsConnectionsFileLoaded = True - 'App.Runtime.Windows.treeForm.InitialRefresh() + IsConnectionsFileLoaded = True + Windows.treeForm.InitialRefresh() + SetSelectedNode(_selectedTreeNode) Catch ex As Exception Throw Finally @@ -282,29 +254,15 @@ Namespace Config End Try End Sub - Private Delegate Sub AddNodeToTreeCB(ByVal TreeNode As TreeNode) - Private Sub AddNodeToTree(ByVal TreeNode As TreeNode) - If Tree.Node.TreeView.InvokeRequired Then - Dim d As New AddNodeToTreeCB(AddressOf AddNodeToTree) - App.Runtime.Windows.treeForm.Invoke(d, New Object() {TreeNode}) - Else - App.Runtime.Windows.treeForm.tvConnections.Nodes.Clear() - App.Runtime.Windows.treeForm.tvConnections.Nodes.Add(TreeNode) - App.Runtime.Windows.treeForm.InitialRefresh() + Private Delegate Sub SetSelectedNodeDelegate(ByVal treeNode As TreeNode) + Private Shared Sub SetSelectedNode(ByVal treeNode As TreeNode) + If Tree.Node.TreeView IsNot Nothing AndAlso Tree.Node.TreeView.InvokeRequired Then + Windows.treeForm.Invoke(New SetSelectedNodeDelegate(AddressOf SetSelectedNode), New Object() {treeNode}) + Return End If + Windows.treeForm.tvConnections.SelectedNode = treeNode End Sub - Private Delegate Sub SetSelectedNodeCB(ByVal TreeNode As TreeNode) - Private Sub SetSelectedNode(ByVal TreeNode As TreeNode) - If Tree.Node.TreeView.InvokeRequired Then - Dim d As New SetSelectedNodeCB(AddressOf SetSelectedNode) - App.Runtime.Windows.treeForm.Invoke(d, New Object() {TreeNode}) - Else - App.Runtime.Windows.treeForm.tvConnections.SelectedNode = TreeNode - End If - End Sub - - Private Sub AddNodesFromSQL(ByVal baseNode As TreeNode) Try sqlCon.Open() @@ -352,7 +310,7 @@ Namespace Config End If If conI.ConstantID = _PreviousSelected Then - selNode = tNode + _selectedTreeNode = tNode End If Else tNode.ImageIndex = Images.Enums.TreeImage.ConnectionClosed @@ -385,7 +343,7 @@ Namespace Config End If If conI.ConstantID = _PreviousSelected Then - selNode = tNode + _selectedTreeNode = tNode End If Else If sqlRd.Item("Expanded") = True Then @@ -669,28 +627,27 @@ Namespace Config End If ' SECTION 2. Initialize the treeview control. - Dim rootNode As TreeNode - Dim rootNodeName As String = "" If xDom.DocumentElement.HasAttribute("Name") Then rootNodeName = xDom.DocumentElement.Attributes("Name").Value.Trim() If Not String.IsNullOrEmpty(rootNodeName) Then - rootNode = New TreeNode(rootNodeName) + RootTreeNode.Name = rootNodeName Else - rootNode = New TreeNode(xDom.DocumentElement.Name) + RootTreeNode.Name = xDom.DocumentElement.Name End If + RootTreeNode.Text = RootTreeNode.Name - Dim rInfo As New Root.Info(Root.Info.RootType.Connection) - rInfo.Name = rootNode.Text - rInfo.TreeNode = rootNode + Dim rootInfo As New Root.Info(Root.Info.RootType.Connection) + rootInfo.Name = RootTreeNode.Name + rootInfo.TreeNode = RootTreeNode - rootNode.Tag = rInfo + RootTreeNode.Tag = rootInfo If Me.confVersion > 1.3 Then '1.4 If Security.Crypt.Decrypt(xDom.DocumentElement.Attributes("Protected").Value, pW) <> "ThisIsNotProtected" Then - If Authenticate(xDom.DocumentElement.Attributes("Protected").Value, False, rInfo) = False Then + If Authenticate(xDom.DocumentElement.Attributes("Protected").Value, False, rootInfo) = False Then My.Settings.LoadConsFromCustomLocation = False My.Settings.CustomConsPath = "" - _RootTreeNode.Remove() + RootTreeNode.Remove() Exit Sub End If End If @@ -709,18 +666,16 @@ Namespace Config End If If Not isExportFile Then - _RootTreeNode.Text = rootNode.Text - _RootTreeNode.Tag = rootNode.Tag - _RootTreeNode.ImageIndex = Images.Enums.TreeImage.Root - _RootTreeNode.SelectedImageIndex = Images.Enums.TreeImage.Root + RootTreeNode.ImageIndex = Images.Enums.TreeImage.Root + RootTreeNode.SelectedImageIndex = Images.Enums.TreeImage.Root End If Windows.treeForm.tvConnections.BeginUpdate() ' SECTION 3. Populate the TreeView with the DOM nodes. - AddNodeFromXml(xDom.DocumentElement, _RootTreeNode) + AddNodeFromXml(xDom.DocumentElement, RootTreeNode) - Me._RootTreeNode.Expand() + RootTreeNode.Expand() 'expand containers For Each contI As Container.Info In Me._ContainerList @@ -733,18 +688,18 @@ Namespace Config 'open connections from last mremote session If My.Settings.OpenConsFromLastSession = True And My.Settings.NoReconnect = False Then - For Each conI As Connection.Info In Me._ConnectionList + For Each conI As Connection.Info In _ConnectionList If conI.PleaseConnect = True Then - App.Runtime.OpenConnection(conI) + OpenConnection(conI) End If Next End If - Me._RootTreeNode.EnsureVisible() + RootTreeNode.EnsureVisible() - - App.Runtime.IsConnectionsFileLoaded = True - App.Runtime.Windows.treeForm.InitialRefresh() + IsConnectionsFileLoaded = True + Windows.treeForm.InitialRefresh() + SetSelectedNode(RootTreeNode) Catch ex As Exception App.Runtime.IsConnectionsFileLoaded = False MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, My.Language.strLoadFromXmlFailed & vbNewLine & ex.Message & vbNewLine & ex.StackTrace, True) @@ -760,7 +715,7 @@ Namespace Config If parentXmlNode.HasChildNodes() Then For Each xmlNode As XmlNode In parentXmlNode.ChildNodes Dim treeNode As TreeNode = New TreeNode(xmlNode.Attributes("Name").Value) - parentTreeNode.Nodes.Add(TreeNode) + parentTreeNode.Nodes.Add(treeNode) If Tree.Node.GetNodeTypeFromString(xmlNode.Attributes("Type").Value) = Tree.Node.Type.Connection Then 'connection info Dim connectionInfo As Connection.Info = GetConnectionInfoFromXml(xmlNode) diff --git a/mRemoteV1/Root/PuttySessions.Info.vb b/mRemoteV1/Root/PuttySessions.Info.vb index 26f9687da..e546562a2 100644 --- a/mRemoteV1/Root/PuttySessions.Info.vb +++ b/mRemoteV1/Root/PuttySessions.Info.vb @@ -10,7 +10,8 @@ Namespace Root MyBase.New(RootType.PuttySessions) End Sub - Private _name As String + Private _name As String = Language.strPuttySavedSessionsRootName + _ Public Overrides Property Name() As String Get Return _name diff --git a/mRemoteV1/Root/Root.Info.vb b/mRemoteV1/Root/Root.Info.vb index 223a70f84..044aa17aa 100644 --- a/mRemoteV1/Root/Root.Info.vb +++ b/mRemoteV1/Root/Root.Info.vb @@ -5,113 +5,57 @@ Imports mRemoteNG.Tools.LocalizedAttributes Namespace Root _ Public Class Info - Public Sub New(ByVal typ As RootType) - _Type = typ +#Region "Constructors" + Public Sub New(ByVal rootType As RootType) + Type = rootType End Sub - -#Region "Properties" - Private _Name As String = My.Language.strConnections - _ - Public Overridable Property Name() As String - Get - Return Me._Name - End Get - Set(ByVal value As String) - Me._Name = value - End Set - End Property - - Private _Password As Boolean - _ - Public Property Password() As Boolean - Get - Return _Password - End Get - Set(ByVal value As Boolean) - _Password = value - End Set - End Property - - Private _PasswordString As String - _ - Public Property PasswordString() As String - Get - Return _PasswordString - End Get - Set(ByVal value As String) - _PasswordString = value - End Set - End Property - - - - - - Private _Type As Root.Info.RootType = RootType.Connection - _ - Public Property Type() As Root.Info.RootType - Get - Return _Type - End Get - Set(ByVal value As Root.Info.RootType) - _Type = value - End Set - End Property - - Private _TreeNode As TreeNode - _ - Public Property TreeNode() As TreeNode - Get - Return Me._TreeNode - End Get - Set(ByVal value As TreeNode) - Me._TreeNode = value - End Set - End Property #End Region +#Region "Public Properties" + Private _name As String = My.Language.strConnections + _ + Public Overridable Property Name() As String + Get + Return _name + End Get + Set(ByVal value As String) + Debug.Print("Root.Info.Name.Set({0})", value) + If _name = value Then Return + _name = value + If TreeNode IsNot Nothing Then + TreeNode.Name = value + TreeNode.Text = value + End If + End Set + End Property + + _ + Public Property Password() As Boolean + + _ + Public Property PasswordString() As String + + _ + Public Property Type() As RootType + + _ + Public Property TreeNode() As TreeNode +#End Region + +#Region "Public Enumerations" Public Enum RootType Connection Credential PuttySessions End Enum - - Public Class Attributes - Public Class Root - Inherits Attribute - End Class - End Class +#End Region End Class End Namespace diff --git a/mRemoteV1/Tools/Tools.LocalizedAttributes.vb b/mRemoteV1/Tools/Tools.LocalizedAttributes.vb index 996941e50..e33c88528 100644 --- a/mRemoteV1/Tools/Tools.LocalizedAttributes.vb +++ b/mRemoteV1/Tools/Tools.LocalizedAttributes.vb @@ -74,6 +74,23 @@ Namespace Tools End Property End Class + _ + Public Class LocalizedDefaultValueAttribute + Inherits DefaultValueAttribute + + Public Sub New(ByVal name As String) + MyBase.New(My.Language.ResourceManager.GetString(name)) + End Sub + + ' This allows localized attributes in a derived class to override a matching + ' non-localized attribute inherited from its base class + Public Overrides ReadOnly Property TypeId() As Object + Get + Return GetType(DefaultValueAttribute) + End Get + End Property + End Class + #Region "Special localization - with String.Format" _ diff --git a/mRemoteV1/UI/UI.Window.Config.vb b/mRemoteV1/UI/UI.Window.Config.vb index f263c1a5a..cc8ff1988 100644 --- a/mRemoteV1/UI/UI.Window.Config.vb +++ b/mRemoteV1/UI/UI.Window.Config.vb @@ -1,5 +1,7 @@ +Imports mRemoteNG.Messages Imports mRemoteNG.My Imports mRemoteNG.Connection.Protocol +Imports mRemoteNG.Root Imports WeifenLuo.WinFormsUI.Docking Imports System.Net.NetworkInformation Imports mRemoteNG.App.Runtime @@ -21,10 +23,16 @@ Namespace UI Private components As System.ComponentModel.IContainer Friend WithEvents propertyGridContextMenu As System.Windows.Forms.ContextMenuStrip Friend WithEvents propertyGridContextMenuShowHelpText As System.Windows.Forms.ToolStripMenuItem + Friend WithEvents propertyGridContextMenuReset As System.Windows.Forms.ToolStripMenuItem + Friend WithEvents ToolStripSeparator1 As System.Windows.Forms.ToolStripSeparator Friend WithEvents pGrid As Azuria.Common.Controls.FilteredPropertyGrid Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container() Me.pGrid = New Azuria.Common.Controls.FilteredPropertyGrid() + Me.propertyGridContextMenu = New System.Windows.Forms.ContextMenuStrip(Me.components) + Me.propertyGridContextMenuReset = New System.Windows.Forms.ToolStripMenuItem() + Me.ToolStripSeparator1 = New System.Windows.Forms.ToolStripSeparator() + Me.propertyGridContextMenuShowHelpText = New System.Windows.Forms.ToolStripMenuItem() Me.btnShowInheritance = New System.Windows.Forms.ToolStripButton() Me.btnShowDefaultInheritance = New System.Windows.Forms.ToolStripButton() Me.btnShowProperties = New System.Windows.Forms.ToolStripButton() @@ -32,8 +40,6 @@ Namespace UI Me.btnIcon = New System.Windows.Forms.ToolStripButton() Me.btnHostStatus = New System.Windows.Forms.ToolStripButton() Me.cMenIcons = New System.Windows.Forms.ContextMenuStrip(Me.components) - Me.propertyGridContextMenu = New System.Windows.Forms.ContextMenuStrip(Me.components) - Me.propertyGridContextMenuShowHelpText = New System.Windows.Forms.ToolStripMenuItem() Me.propertyGridContextMenu.SuspendLayout() Me.SuspendLayout() ' @@ -54,6 +60,29 @@ Namespace UI Me.pGrid.TabIndex = 0 Me.pGrid.UseCompatibleTextRendering = True ' + 'propertyGridContextMenu + ' + Me.propertyGridContextMenu.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.propertyGridContextMenuReset, Me.ToolStripSeparator1, Me.propertyGridContextMenuShowHelpText}) + Me.propertyGridContextMenu.Name = "propertyGridContextMenu" + Me.propertyGridContextMenu.Size = New System.Drawing.Size(157, 76) + ' + 'propertyGridContextMenuReset + ' + Me.propertyGridContextMenuReset.Name = "propertyGridContextMenuReset" + Me.propertyGridContextMenuReset.Size = New System.Drawing.Size(156, 22) + Me.propertyGridContextMenuReset.Text = "&Reset" + ' + 'ToolStripSeparator1 + ' + Me.ToolStripSeparator1.Name = "ToolStripSeparator1" + Me.ToolStripSeparator1.Size = New System.Drawing.Size(153, 6) + ' + 'propertyGridContextMenuShowHelpText + ' + Me.propertyGridContextMenuShowHelpText.Name = "propertyGridContextMenuShowHelpText" + Me.propertyGridContextMenuShowHelpText.Size = New System.Drawing.Size(156, 22) + Me.propertyGridContextMenuShowHelpText.Text = "&Show Help Text" + ' 'btnShowInheritance ' Me.btnShowInheritance.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image @@ -117,18 +146,6 @@ Namespace UI Me.cMenIcons.Name = "cMenIcons" Me.cMenIcons.Size = New System.Drawing.Size(61, 4) ' - 'propertyGridContextMenu - ' - Me.propertyGridContextMenu.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.propertyGridContextMenuShowHelpText}) - Me.propertyGridContextMenu.Name = "propertyGridContextMenu" - Me.propertyGridContextMenu.Size = New System.Drawing.Size(157, 26) - ' - 'propertyGridContextMenuShowHelpText - ' - Me.propertyGridContextMenuShowHelpText.Name = "ContextMenuShowHelpText" - Me.propertyGridContextMenuShowHelpText.Size = New System.Drawing.Size(156, 22) - Me.propertyGridContextMenuShowHelpText.Text = "&Show Help Text" - ' 'Config ' Me.ClientSize = New System.Drawing.Size(226, 530) @@ -629,22 +646,21 @@ Namespace UI End If End If - If TypeOf Me.pGrid.SelectedObject Is mRemoteNG.Root.Info Then - Dim rInfo As mRemoteNG.Root.Info = Me.pGrid.SelectedObject + Dim rootInfo As Info = TryCast(pGrid.SelectedObject, Info) + If (rootInfo IsNot Nothing) Then + Select Case e.ChangedItem.PropertyDescriptor.Name + Case "Password" + If rootInfo.Password = True Then + Dim password As String = Tools.Misc.PasswordDialog - Select Case e.ChangedItem.Label - Case My.Language.strPasswordProtect - If rInfo.Password = True Then - Dim pw As String = Tools.Misc.PasswordDialog - - If pw <> "" Then - rInfo.PasswordString = pw + If String.IsNullOrEmpty(password) Then + rootInfo.Password = False Else - rInfo.Password = False + rootInfo.PasswordString = password End If End If - Case My.Language.strPropertyNameName - App.Runtime.Windows.treeForm.tvConnections.SelectedNode.Text = Me.pGrid.SelectedObject.Name + Case "Name" + 'Windows.treeForm.tvConnections.SelectedNode.Text = pGrid.SelectedObject.Name End Select End If @@ -1505,14 +1521,37 @@ Namespace UI #End Region Private Sub propertyGridContextMenu_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles propertyGridContextMenu.Opening - propertyGridContextMenuShowHelpText.Checked = Settings.ShowConfigHelpText + Try + propertyGridContextMenuShowHelpText.Checked = Settings.ShowConfigHelpText + Dim gridItem As GridItem = pGrid.SelectedGridItem + propertyGridContextMenuReset.Enabled = (pGrid.SelectedObject IsNot Nothing AndAlso _ + gridItem IsNot Nothing AndAlso _ + gridItem.PropertyDescriptor IsNot Nothing AndAlso _ + gridItem.PropertyDescriptor.CanResetValue(pGrid.SelectedObject)) + Catch ex As Exception + MessageCollector.AddExceptionMessage("UI.Window.Config.propertyGridContextMenu_Opening() failed.", ex, MessageClass.ErrorMsg, True) + End Try End Sub - Private Sub propertyGridContextMenu_Click(sender As Object, e As EventArgs) Handles propertyGridContextMenuShowHelpText.Click + Private Sub propertyGridContextMenuReset_Click(sender As System.Object, e As EventArgs) Handles propertyGridContextMenuReset.Click + Try + Dim gridItem As GridItem = pGrid.SelectedGridItem + If pGrid.SelectedObject IsNot Nothing AndAlso _ + gridItem IsNot Nothing AndAlso _ + gridItem.PropertyDescriptor IsNot Nothing AndAlso _ + gridItem.PropertyDescriptor.CanResetValue(pGrid.SelectedObject) Then + pGrid.ResetSelectedProperty() + End If + Catch ex As Exception + MessageCollector.AddExceptionMessage("UI.Window.Config.propertyGridContextMenuReset_Click() failed.", ex, MessageClass.ErrorMsg, True) + End Try + End Sub + + Private Sub propertyGridContextMenuShowHelpText_Click(sender As Object, e As EventArgs) Handles propertyGridContextMenuShowHelpText.Click propertyGridContextMenuShowHelpText.Checked = Not propertyGridContextMenuShowHelpText.Checked End Sub - Private Sub propertyGridContextMenu_CheckedChanged(sender As Object, e As EventArgs) Handles propertyGridContextMenuShowHelpText.CheckedChanged + Private Sub propertyGridContextMenuShowHelpText_CheckedChanged(sender As Object, e As EventArgs) Handles propertyGridContextMenuShowHelpText.CheckedChanged Settings.ShowConfigHelpText = propertyGridContextMenuShowHelpText.Checked pGrid.HelpVisible = propertyGridContextMenuShowHelpText.Checked End Sub From 1c33494547b0f5aff7599da883b1c3a9d10e92f4 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Sun, 27 Oct 2013 01:54:48 -0500 Subject: [PATCH 14/18] Update version number to 1.72. --- mRemoteV1/My Project/AssemblyInfo.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/My Project/AssemblyInfo.vb b/mRemoteV1/My Project/AssemblyInfo.vb index 63e988063..ce9da8d28 100644 --- a/mRemoteV1/My Project/AssemblyInfo.vb +++ b/mRemoteV1/My Project/AssemblyInfo.vb @@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices ' by using the '*' as shown below: ' - + From 2e663df42a0cc9f26f335bdfb7a88fbafc4bdc39 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Sun, 27 Oct 2013 05:46:11 -0500 Subject: [PATCH 15/18] Fix issue MR-578 - Connections file is reset Fix the wrong connections file opening on startup under certain conditions. Improve error reporting when loading connections files. Remove warning message when mRemoteNG is started for the first time about new connections file being created. --- CHANGELOG.TXT | 4 + mRemoteV1/App/App.Runtime.vb | 175 +++++++++++++++++----------------- mRemoteV1/Forms/frmMain.vb | 6 ++ mRemoteV1/Forms/frmOptions.vb | 6 +- 4 files changed, 99 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 83ce2428b..5b2469cc9 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,6 +1,10 @@ 1.71 (XXXX-XX-XX): Fixed issue MR-574 - Crash when retrieving RDP session list if eolwtscom.dll is not registered + Fixed issue MR-578 - Connections file is reset Fixed log file not showing operating system version on Windows XP and Windows Server 2003. + Fixed the wrong connections file opening on startup under certain conditions. + Improved error reporting when loading connections files. + Removed warning message when mRemoteNG is started for the first time about new connections file being created. 1.71 Release Candidate 2 (2013-10-16): Fixed issue MR-560 - Cannot Auto-Update With Open Connections: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32' diff --git a/mRemoteV1/App/App.Runtime.vb b/mRemoteV1/App/App.Runtime.vb index d6f983e32..7fcb05d87 100644 --- a/mRemoteV1/App/App.Runtime.vb +++ b/mRemoteV1/App/App.Runtime.vb @@ -989,41 +989,54 @@ Namespace App ConnectionList = New Connection.List ContainerList = New Container.List - Dim conL As New Config.Connections.Load + Dim connectionsLoad As New Connections.Load - My.Settings.LoadConsFromCustomLocation = False + If filename = GetDefaultStartupConnectionFileName() Then + My.Settings.LoadConsFromCustomLocation = False + Else + My.Settings.LoadConsFromCustomLocation = True + My.Settings.CustomConsPath = filename + End If Directory.CreateDirectory(Path.GetDirectoryName(filename)) - Dim xW As New XmlTextWriter(filename, System.Text.Encoding.UTF8) - xW.Formatting = Formatting.Indented - xW.Indentation = 4 - xW.WriteStartDocument() - xW.WriteStartElement("Connections") ' Do not localize - xW.WriteAttributeString("Name", My.Language.strConnections) - xW.WriteAttributeString("Export", "", "False") - xW.WriteAttributeString("Protected", "", "GiUis20DIbnYzWPcdaQKfjE2H5jh//L5v4RGrJMGNXuIq2CttB/d/BxaBP2LwRhY") - xW.WriteAttributeString("ConfVersion", "", "2.5") + ' Use File.Open with FileMode.CreateNew so that we don't overwrite an existing file + Using fileStream As FileStream = File.Open(filename, FileMode.CreateNew, FileAccess.Write, FileShare.None) + Using xmlTextWriter As New XmlTextWriter(fileStream, System.Text.Encoding.UTF8) + With xmlTextWriter + .Formatting = Formatting.Indented + .Indentation = 4 - xW.WriteEndElement() - xW.WriteEndDocument() + .WriteStartDocument() - xW.Close() + .WriteStartElement("Connections") ' Do not localize + .WriteAttributeString("Name", My.Language.strConnections) + .WriteAttributeString("Export", "", "False") + .WriteAttributeString("Protected", "", "GiUis20DIbnYzWPcdaQKfjE2H5jh//L5v4RGrJMGNXuIq2CttB/d/BxaBP2LwRhY") + .WriteAttributeString("ConfVersion", "", "2.5") - conL.ConnectionList = ConnectionList - conL.ContainerList = ContainerList + .WriteEndElement() + .WriteEndDocument() + + .Close() + End With + End Using + End Using + + connectionsLoad.ConnectionList = ConnectionList + connectionsLoad.ContainerList = ContainerList Tree.Node.ResetTree() - conL.RootTreeNode = Windows.treeForm.tvConnections.Nodes(0) + connectionsLoad.RootTreeNode = Windows.treeForm.tvConnections.Nodes(0) ' Load config - conL.ConnectionFileName = filename - conL.Load(False) + connectionsLoad.ConnectionFileName = filename + connectionsLoad.Load(False) - Windows.treeForm.tvConnections.SelectedNode = conL.RootTreeNode + Windows.treeForm.tvConnections.SelectedNode = connectionsLoad.RootTreeNode Catch ex As Exception - MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, My.Language.strCouldNotCreateNewConnectionsFile & vbNewLine & ex.Message) + MessageCollector.AddExceptionMessage(My.Language.strCouldNotCreateNewConnectionsFile, ex, MessageClass.ErrorMsg) End Try End Sub @@ -1042,8 +1055,8 @@ Namespace App LoadConnections(_withDialog, _loadUpdate) End Sub - Public Shared Sub LoadConnections(Optional ByVal WithDialog As Boolean = False, Optional ByVal Update As Boolean = False) - Dim conL As New Config.Connections.Load + Public Shared Sub LoadConnections(Optional ByVal withDialog As Boolean = False, Optional ByVal update As Boolean = False) + Dim connectionsLoad As New Connections.Load Try Dim tmrWasEnabled As Boolean @@ -1063,66 +1076,55 @@ Namespace App ConnectionList = New Connection.List ContainerList = New Container.List - If My.Settings.UseSQLServer = False Then - If WithDialog Then - Dim lD As OpenFileDialog = Tools.Controls.ConnectionsLoadDialog + If Not My.Settings.UseSQLServer Then + If withDialog Then + Dim loadDialog As OpenFileDialog = Controls.ConnectionsLoadDialog - If lD.ShowDialog = System.Windows.Forms.DialogResult.OK Then - conL.ConnectionFileName = lD.FileName + If loadDialog.ShowDialog = System.Windows.Forms.DialogResult.OK Then + connectionsLoad.ConnectionFileName = loadDialog.FileName Else Exit Sub End If Else - conL.ConnectionFileName = GetStartupConnectionFileName() + connectionsLoad.ConnectionFileName = GetStartupConnectionFileName() End If - If File.Exists(conL.ConnectionFileName) = False Then - If WithDialog Then - MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, String.Format(My.Language.strConnectionsFileCouldNotBeLoaded, conL.ConnectionFileName)) - Else - MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, String.Format(My.Language.strConnectionsFileCouldNotBeLoadedNew, conL.ConnectionFileName)) - App.Runtime.NewConnections(conL.ConnectionFileName) - End If - - Exit Sub - End If - - CreateBackupFile(conL.ConnectionFileName) + CreateBackupFile(connectionsLoad.ConnectionFileName) End If - conL.ConnectionList = ConnectionList - conL.ContainerList = ContainerList + connectionsLoad.ConnectionList = ConnectionList + connectionsLoad.ContainerList = ContainerList If PreviousConnectionList IsNot Nothing And PreviousContainerList IsNot Nothing Then - conL.PreviousConnectionList = PreviousConnectionList - conL.PreviousContainerList = PreviousContainerList + connectionsLoad.PreviousConnectionList = PreviousConnectionList + connectionsLoad.PreviousContainerList = PreviousContainerList End If - If Update = True Then - conL.PreviousSelected = LastSelected + If update = True Then + connectionsLoad.PreviousSelected = LastSelected End If Tree.Node.ResetTree() - conL.RootTreeNode = Windows.treeForm.tvConnections.Nodes(0) + connectionsLoad.RootTreeNode = Windows.treeForm.tvConnections.Nodes(0) - conL.UseSQL = My.Settings.UseSQLServer - conL.SQLHost = My.Settings.SQLHost - conL.SQLDatabaseName = My.Settings.SQLDatabaseName - conL.SQLUsername = My.Settings.SQLUser - conL.SQLPassword = Security.Crypt.Decrypt(My.Settings.SQLPass, App.Info.General.EncryptionKey) - conL.SQLUpdate = Update + connectionsLoad.UseSQL = My.Settings.UseSQLServer + connectionsLoad.SQLHost = My.Settings.SQLHost + connectionsLoad.SQLDatabaseName = My.Settings.SQLDatabaseName + connectionsLoad.SQLUsername = My.Settings.SQLUser + connectionsLoad.SQLPassword = Security.Crypt.Decrypt(My.Settings.SQLPass, Info.General.EncryptionKey) + connectionsLoad.SQLUpdate = update - conL.Load(False) + connectionsLoad.Load(False) If My.Settings.UseSQLServer = True Then LastSqlUpdate = Now Else - If conL.ConnectionFileName = App.Info.Connections.DefaultConnectionsPath & "\" & App.Info.Connections.DefaultConnectionsFile Then + If connectionsLoad.ConnectionFileName = GetDefaultStartupConnectionFileName() Then My.Settings.LoadConsFromCustomLocation = False Else My.Settings.LoadConsFromCustomLocation = True - My.Settings.CustomConsPath = conL.ConnectionFileName + My.Settings.CustomConsPath = connectionsLoad.ConnectionFileName End If End If @@ -1136,20 +1138,26 @@ Namespace App cTaskDialog.ShowCommandBox(Application.ProductName, My.Language.strLoadFromSqlFailed, My.Language.strLoadFromSqlFailedContent, Misc.GetExceptionMessageRecursive(ex), "", "", commandButtons, False, eSysIcons.Error, Nothing) Select Case cTaskDialog.CommandButtonResult Case 0 - LoadConnections(WithDialog, Update) + LoadConnections(withDialog, update) Return Case 1 My.Settings.UseSQLServer = False - LoadConnections(True, Update) + LoadConnections(True, update) Return Case Else Application.Exit() Return End Select Else - MessageCollector.AddExceptionMessage(String.Format(My.Language.strConnectionsFileCouldNotBeLoaded, conL.ConnectionFileName), ex) - If Not conL.ConnectionFileName = GetStartupConnectionFileName() Then - LoadConnections(WithDialog, Update) + If TypeOf ex Is FileNotFoundException And Not withDialog Then + MessageCollector.AddExceptionMessage(String.Format(My.Language.strConnectionsFileCouldNotBeLoadedNew, connectionsLoad.ConnectionFileName), ex, MessageClass.InformationMsg) + NewConnections(connectionsLoad.ConnectionFileName) + Return + End If + + MessageCollector.AddExceptionMessage(String.Format(My.Language.strConnectionsFileCouldNotBeLoaded, connectionsLoad.ConnectionFileName), ex) + If Not connectionsLoad.ConnectionFileName = GetStartupConnectionFileName() Then + LoadConnections(withDialog, update) Return Else MsgBox(String.Format(My.Language.strErrorStartupConnectionFileLoad, vbNewLine, Application.ProductName, GetStartupConnectionFileName(), Misc.GetExceptionMessageRecursive(ex)), MsgBoxStyle.OkOnly + MsgBoxStyle.Critical) @@ -1169,7 +1177,7 @@ Namespace App File.Copy(fileName, backupFileName) PruneBackupFiles(fileName) Catch ex As Exception - MessageCollector.AddMessage(MessageClass.WarningMsg, My.Language.strConnectionsFileBackupFailed & vbNewLine & vbNewLine & ex.Message) + MessageCollector.AddExceptionMessage(My.Language.strConnectionsFileBackupFailed, ex, MessageClass.WarningMsg) Throw End Try End Sub @@ -1193,26 +1201,23 @@ Namespace App Next End Sub - Protected Shared Function GetStartupConnectionFileName() As String - Dim fileName As New String("") - - If My.Settings.LoadConsFromCustomLocation = False Then - Dim oldPath As String = GetFolderPath(SpecialFolder.LocalApplicationData) & "\" & My.Application.Info.ProductName & "\" & App.Info.Connections.DefaultConnectionsFile - Dim newPath As String = App.Info.Connections.DefaultConnectionsPath & "\" & App.Info.Connections.DefaultConnectionsFile + Public Shared Function GetDefaultStartupConnectionFileName() As String + Dim newPath As String = App.Info.Connections.DefaultConnectionsPath & "\" & Info.Connections.DefaultConnectionsFile #If Not PORTABLE Then - If File.Exists(oldPath) Then - fileName = oldPath - Else - fileName = newPath - End If -#Else - fileName = newPath -#End If - Else - fileName = My.Settings.CustomConsPath + Dim oldPath As String = GetFolderPath(SpecialFolder.LocalApplicationData) & "\" & My.Application.Info.ProductName & "\" & Info.Connections.DefaultConnectionsFile + If File.Exists(oldPath) Then + Return oldPath End If +#End If + Return newPath + End Function - Return fileName + Public Shared Function GetStartupConnectionFileName() As String + If My.Settings.LoadConsFromCustomLocation = False Then + Return GetDefaultStartupConnectionFileName() + Else + Return My.Settings.CustomConsPath + End If End Function Public Shared Sub ImportConnections() @@ -1497,12 +1502,8 @@ Namespace App Dim conS As New Config.Connections.Save - If My.Settings.UseSQLServer = False Then - If My.Settings.LoadConsFromCustomLocation = False Then - conS.ConnectionFileName = App.Info.Connections.DefaultConnectionsPath & "\" & App.Info.Connections.DefaultConnectionsFile - Else - conS.ConnectionFileName = My.Settings.CustomConsPath - End If + If Not My.Settings.UseSQLServer Then + conS.ConnectionFileName = GetStartupConnectionFileName() End If conS.ConnectionList = ConnectionList @@ -1571,7 +1572,7 @@ Namespace App Else connectionsSave.SaveFormat = Config.Connections.Save.Format.mRXML - If connectionsSave.ConnectionFileName = Info.Connections.DefaultConnectionsPath & "\" & Info.Connections.DefaultConnectionsFile Then + If connectionsSave.ConnectionFileName = GetDefaultStartupConnectionFileName() Then My.Settings.LoadConsFromCustomLocation = False Else My.Settings.LoadConsFromCustomLocation = True diff --git a/mRemoteV1/Forms/frmMain.vb b/mRemoteV1/Forms/frmMain.vb index 231105675..eadf76485 100644 --- a/mRemoteV1/Forms/frmMain.vb +++ b/mRemoteV1/Forms/frmMain.vb @@ -67,6 +67,12 @@ Public Class frmMain Tree.Node.TreeView = Windows.treeForm.tvConnections + If My.Settings.FirstStart And _ + Not My.Settings.LoadConsFromCustomLocation And _ + Not IO.File.Exists(GetStartupConnectionFileName()) Then + NewConnections(GetStartupConnectionFileName()) + End If + 'LoadCredentials() LoadConnections() If Not IsConnectionsFileLoaded Then diff --git a/mRemoteV1/Forms/frmOptions.vb b/mRemoteV1/Forms/frmOptions.vb index 136b16128..70bc0e8b4 100644 --- a/mRemoteV1/Forms/frmOptions.vb +++ b/mRemoteV1/Forms/frmOptions.vb @@ -1810,11 +1810,7 @@ Public Class frmOptions ThemeManager.SaveThemes(_themeList) Settings.ThemeName = ThemeManager.ActiveTheme.Name - If My.Settings.LoadConsFromCustomLocation = False Then - App.Runtime.SetMainFormText(App.Info.Connections.DefaultConnectionsPath & "\" & App.Info.Connections.DefaultConnectionsFile) - Else - App.Runtime.SetMainFormText(My.Settings.CustomConsPath) - End If + SetMainFormText(GetStartupConnectionFileName()) App.Runtime.Startup.DestroySQLUpdateHandlerAndStopTimer() From 869c2726bb351347f4fd1d28908e0c27b476c461 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Sun, 27 Oct 2013 06:04:54 -0500 Subject: [PATCH 16/18] Fix checking for updates even when disabled. --- CHANGELOG.TXT | 1 + mRemoteV1/Forms/frmMain.vb | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 5b2469cc9..9b84dfd21 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -3,6 +3,7 @@ Fixed issue MR-578 - Connections file is reset Fixed log file not showing operating system version on Windows XP and Windows Server 2003. Fixed the wrong connections file opening on startup under certain conditions. + Fixed checking for updates even when disabled. Improved error reporting when loading connections files. Removed warning message when mRemoteNG is started for the first time about new connections file being created. diff --git a/mRemoteV1/Forms/frmMain.vb b/mRemoteV1/Forms/frmMain.vb index eadf76485..4e0ca762d 100644 --- a/mRemoteV1/Forms/frmMain.vb +++ b/mRemoteV1/Forms/frmMain.vb @@ -206,7 +206,9 @@ Public Class frmMain End Sub Private Sub frmMain_Shown(sender As Object, e As EventArgs) Handles Me.Shown -#If Not PORTABLE Then +#If PORTABLE Then + Return +#End If If Not My.Settings.CheckForUpdatesAsked Then Dim commandButtons() As String = {My.Language.strAskUpdatesCommandRecommended, My.Language.strAskUpdatesCommandCustom, My.Language.strAskUpdatesCommandAskLater} cTaskDialog.ShowTaskDialogBox(Me, My.Application.Info.ProductName, My.Language.strAskUpdatesMainInstruction, String.Format(My.Language.strAskUpdatesContent, My.Application.Info.ProductName), "", "", "", "", String.Join("|", commandButtons), eTaskDialogButtons.None, eSysIcons.Question, eSysIcons.Question) @@ -216,15 +218,17 @@ Public Class frmMain If cTaskDialog.CommandButtonResult = 1 Then Windows.ShowUpdatesTab() End If + Return End If + If Not My.Settings.CheckForUpdatesOnStartup Then Return + Dim nextUpdateCheck As Date = My.Settings.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(My.Settings.CheckForUpdatesFrequencyDays)) If My.Settings.UpdatePending Or Date.UtcNow > nextUpdateCheck Then If Not IsHandleCreated Then CreateHandle() ' Make sure the handle is created so that InvokeRequired returns the correct result Startup.CheckForUpdate() Startup.CheckForAnnouncement() End If -#End If End Sub Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing From f5cde10d62c651bb053b97cc98bfdfe3cd963f23 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 28 Oct 2013 01:06:36 -0500 Subject: [PATCH 17/18] Fix merge error. --- mRemoteV1/App/App.Runtime.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mRemoteV1/App/App.Runtime.vb b/mRemoteV1/App/App.Runtime.vb index 89acd4cc8..236904604 100644 --- a/mRemoteV1/App/App.Runtime.vb +++ b/mRemoteV1/App/App.Runtime.vb @@ -1068,7 +1068,7 @@ Namespace App If Not My.Settings.UseSQLServer Then If withDialog Then - Dim loadDialog As OpenFileDialog = Controls.ConnectionsLoadDialog + Dim loadDialog As OpenFileDialog = Tools.Controls.ConnectionsLoadDialog If loadDialog.ShowDialog = System.Windows.Forms.DialogResult.OK Then connectionsLoad.ConnectionFileName = loadDialog.FileName From e96199dc37310d5feb4732d3cbb197897f1f65e5 Mon Sep 17 00:00:00 2001 From: Riley McArdle Date: Mon, 28 Oct 2013 01:14:59 -0500 Subject: [PATCH 18/18] Change XmingProvider to include sessions from the registry. --- .../Config/Putty/DefaultSettingsProvider.vb | 21 ---- mRemoteV1/Config/Putty/Provider.vb | 92 ++++++++------- mRemoteV1/Config/Putty/RegistryProvider.vb | 25 +++-- mRemoteV1/Config/Putty/Sessions.vb | 75 +++++++------ mRemoteV1/Config/Putty/XmingProvider.vb | 105 ++++++++++++++---- mRemoteV1/mRemoteV1.vbproj | 1 - 6 files changed, 189 insertions(+), 130 deletions(-) delete mode 100644 mRemoteV1/Config/Putty/DefaultSettingsProvider.vb diff --git a/mRemoteV1/Config/Putty/DefaultSettingsProvider.vb b/mRemoteV1/Config/Putty/DefaultSettingsProvider.vb deleted file mode 100644 index d7c9d5e07..000000000 --- a/mRemoteV1/Config/Putty/DefaultSettingsProvider.vb +++ /dev/null @@ -1,21 +0,0 @@ -Imports mRemoteNG.Connection.PuttySession - -Namespace Config.Putty - Public Class DefaultSettingsProvider - Inherits Provider - - Public Overrides Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() - Dim sessionNames(0) As String - If raw Then - sessionNames(0) = "Default%20Settings" - Else - sessionNames(0) = "Default Settings" - End If - Return sessionNames - End Function - - Public Overrides Function GetSession(ByVal sessionName As String) As Info - Return Nothing - End Function - End Class -End Namespace diff --git a/mRemoteV1/Config/Putty/Provider.vb b/mRemoteV1/Config/Putty/Provider.vb index ae0816da2..b40d7b4c5 100644 --- a/mRemoteV1/Config/Putty/Provider.vb +++ b/mRemoteV1/Config/Putty/Provider.vb @@ -2,6 +2,7 @@ Namespace Config.Putty Public MustInherit Class Provider +#Region "Public Methods" Private _rootTreeNode As TreeNode Public ReadOnly Property RootTreeNode As TreeNode Get @@ -10,26 +11,6 @@ Namespace Config.Putty End Get End Property - Private Delegate Function CreateRootTreeNodeDelegate() As TreeNode - Protected Overridable Function CreateRootTreeNode() As TreeNode - Dim treeView As TreeView = Tree.Node.TreeView - If treeView Is Nothing Then Return Nothing - If treeView.InvokeRequired Then - Return treeView.Invoke(New CreateRootTreeNodeDelegate(AddressOf CreateRootTreeNode)) - End If - - Dim newTreeNode As New TreeNode - RootInfo.TreeNode = newTreeNode - - newTreeNode.Name = _rootInfo.Name - newTreeNode.Text = _rootInfo.Name - newTreeNode.Tag = _rootInfo - newTreeNode.ImageIndex = Images.Enums.TreeImage.PuttySessions - newTreeNode.SelectedImageIndex = Images.Enums.TreeImage.PuttySessions - - Return newTreeNode - End Function - Private _rootInfo As Root.PuttySessions.Info Public ReadOnly Property RootInfo() As Root.PuttySessions.Info Get @@ -38,24 +19,6 @@ Namespace Config.Putty End Get End Property - Protected Overridable Function CreateRootInfo() As Root.PuttySessions.Info - Dim newRootInfo As New Root.PuttySessions.Info - - If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsName) Then - newRootInfo.Name = Language.strPuttySavedSessionsRootName - Else - newRootInfo.Name = My.Settings.PuttySavedSessionsName - End If - - If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsPanel) Then - newRootInfo.Panel = Language.strGeneral - Else - newRootInfo.Panel = My.Settings.PuttySavedSessionsPanel - End If - - Return newRootInfo - End Function - Public MustOverride Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() Public MustOverride Function GetSession(ByVal sessionName As String) As Connection.PuttySession.Info @@ -77,15 +40,60 @@ Namespace Config.Putty Public Overridable Sub StopWatcher() End Sub +#End Region +#Region "Public Events" Public Event SessionChanged(ByVal sender As Object, ByVal e As SessionChangedEventArgs) +#End Region + +#Region "Public Classes" + Public Class SessionChangedEventArgs + Inherits EventArgs + End Class +#End Region + +#Region "Protected Methods" + Private Delegate Function CreateRootTreeNodeDelegate() As TreeNode + Protected Overridable Function CreateRootTreeNode() As TreeNode + Dim treeView As TreeView = Tree.Node.TreeView + If treeView Is Nothing Then Return Nothing + If treeView.InvokeRequired Then + Return treeView.Invoke(New CreateRootTreeNodeDelegate(AddressOf CreateRootTreeNode)) + End If + + Dim newTreeNode As New TreeNode + RootInfo.TreeNode = newTreeNode + + newTreeNode.Name = _rootInfo.Name + newTreeNode.Text = _rootInfo.Name + newTreeNode.Tag = _rootInfo + newTreeNode.ImageIndex = Images.Enums.TreeImage.PuttySessions + newTreeNode.SelectedImageIndex = Images.Enums.TreeImage.PuttySessions + + Return newTreeNode + End Function + + Protected Overridable Function CreateRootInfo() As Root.PuttySessions.Info + Dim newRootInfo As New Root.PuttySessions.Info + + If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsName) Then + newRootInfo.Name = Language.strPuttySavedSessionsRootName + Else + newRootInfo.Name = My.Settings.PuttySavedSessionsName + End If + + If String.IsNullOrEmpty(My.Settings.PuttySavedSessionsPanel) Then + newRootInfo.Panel = Language.strGeneral + Else + newRootInfo.Panel = My.Settings.PuttySavedSessionsPanel + End If + + Return newRootInfo + End Function Protected Overridable Sub OnSessionChanged(ByVal e As SessionChangedEventArgs) RaiseEvent SessionChanged(Me, New SessionChangedEventArgs()) End Sub - - Public Class SessionChangedEventArgs - Inherits EventArgs - End Class +#End Region End Class End Namespace diff --git a/mRemoteV1/Config/Putty/RegistryProvider.vb b/mRemoteV1/Config/Putty/RegistryProvider.vb index 3c6940366..eabaab200 100644 --- a/mRemoteV1/Config/Putty/RegistryProvider.vb +++ b/mRemoteV1/Config/Putty/RegistryProvider.vb @@ -9,9 +9,7 @@ Namespace Config.Putty Public Class RegistryProvider Inherits Provider - Private Const PuttySessionsKey As String = "Software\SimonTatham\PuTTY\Sessions" - Private Shared _eventWatcher As ManagementEventWatcher - +#Region "Public Methods" Public Overrides Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() Dim sessionsKey As RegistryKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey) If sessionsKey Is Nothing Then Return New String() {} @@ -25,11 +23,14 @@ Namespace Config.Putty End If Next - If sessionNames.Contains("Default%20Settings") Then ' Do not localize - sessionNames.Remove("Default%20Settings") - End If - If sessionNames.Contains("Default Settings") Then - sessionNames.Remove("Default Settings") + If raw Then + If Not sessionNames.Contains("Default%20Settings") Then ' Do not localize + sessionNames.Insert(0, "Default%20Settings") + End If + Else + If Not sessionNames.Contains("Default Settings") Then + sessionNames.Insert(0, "Default Settings") + End If End If Return sessionNames.ToArray() @@ -103,10 +104,18 @@ Namespace Config.Putty _eventWatcher.Dispose() _eventWatcher = Nothing End Sub +#End Region +#Region "Private Fields" + Private Const PuttySessionsKey As String = "Software\SimonTatham\PuTTY\Sessions" + Private Shared _eventWatcher As ManagementEventWatcher +#End Region + +#Region "Private Methods" Private Sub OnManagementEventArrived(ByVal sender As Object, ByVal e As EventArrivedEventArgs) OnSessionChanged(New SessionChangedEventArgs()) End Sub +#End Region End Class End Namespace diff --git a/mRemoteV1/Config/Putty/Sessions.vb b/mRemoteV1/Config/Putty/Sessions.vb index 8f389442a..7ae3ec271 100644 --- a/mRemoteV1/Config/Putty/Sessions.vb +++ b/mRemoteV1/Config/Putty/Sessions.vb @@ -3,21 +3,7 @@ Imports mRemoteNG.Tools Namespace Config.Putty Public Class Sessions - Private Shared _providers As List(Of Provider) - Private Shared ReadOnly Property Providers() As List(Of Provider) - Get - If _providers Is Nothing OrElse _providers.Count = 0 Then AddProviders() - Return _providers - End Get - End Property - - Private Shared Sub AddProviders() - _providers = New List(Of Provider)() - _providers.Add(New DefaultSettingsProvider()) - _providers.Add(New RegistryProvider()) - _providers.Add(New XmingProvider()) - End Sub - +#Region "Public Methods" Private Delegate Sub AddSessionsToTreeDelegate() Public Shared Sub AddSessionsToTree() Dim treeView As TreeView = Tree.Node.TreeView @@ -27,22 +13,12 @@ Namespace Config.Putty Return End If - Dim puttyType As PuttyTypeDetector.PuttyType = PuttyTypeDetector.GetPuttyType() - For Each provider As Provider In Providers - Dim enabled As Boolean = True - Select Case puttyType - Case PuttyTypeDetector.PuttyType.Xming - If TypeOf (provider) Is RegistryProvider Then enabled = False - Case Else - If TypeOf (provider) Is XmingProvider Then enabled = False - End Select - Dim rootTreeNode As TreeNode = provider.RootTreeNode Dim inUpdate As Boolean = False Dim savedSessions As New List(Of Connection.Info)(provider.GetSessions()) - If Not enabled Or savedSessions Is Nothing OrElse savedSessions.Count = 0 Then + If Not IsProviderEnabled(provider) Or savedSessions Is Nothing OrElse savedSessions.Count = 0 Then If rootTreeNode IsNot Nothing AndAlso treeView.Nodes.Contains(rootTreeNode) Then treeView.BeginUpdate() treeView.Nodes.Remove(rootTreeNode) @@ -110,14 +86,6 @@ Namespace Config.Putty Next End Sub - Protected Shared Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() - Dim sessionNames As New List(Of String) - For Each provider As Provider In Providers - sessionNames.AddRange(provider.GetSessionNames()) - Next - Return sessionNames.ToArray() - End Function - Public Shared Sub StartWatcher() For Each provider As Provider In Providers provider.StartWatcher() @@ -135,7 +103,45 @@ Namespace Config.Putty Public Shared Sub SessionChanged(ByVal sender As Object, ByVal e As Provider.SessionChangedEventArgs) AddSessionsToTree() End Sub +#End Region +#Region "Private Methods" + Private Shared _providers As List(Of Provider) + Private Shared ReadOnly Property Providers() As List(Of Provider) + Get + If _providers Is Nothing OrElse _providers.Count = 0 Then AddProviders() + Return _providers + End Get + End Property + + Private Shared Sub AddProviders() + _providers = New List(Of Provider)() + _providers.Add(New RegistryProvider()) + _providers.Add(New XmingProvider()) + End Sub + + Private Shared Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() + Dim sessionNames As New List(Of String) + For Each provider As Provider In Providers + If Not IsProviderEnabled(provider) Then Continue For + sessionNames.AddRange(provider.GetSessionNames(raw)) + Next + Return sessionNames.ToArray() + End Function + + Private Shared Function IsProviderEnabled(ByVal provider As Provider) As Boolean + Dim enabled As Boolean = True + Select Case PuttyTypeDetector.GetPuttyType() + Case PuttyTypeDetector.PuttyType.Xming + If TypeOf (provider) Is RegistryProvider Then enabled = False + Case Else + If TypeOf (provider) Is XmingProvider Then enabled = False + End Select + Return enabled + End Function +#End Region + +#Region "Public Classes" Public Class SessionList Inherits StringConverter @@ -157,5 +163,6 @@ Namespace Config.Putty Return True End Function End Class +#End Region End Class End Namespace diff --git a/mRemoteV1/Config/Putty/XmingProvider.vb b/mRemoteV1/Config/Putty/XmingProvider.vb index 84fbb2629..17b509ea2 100644 --- a/mRemoteV1/Config/Putty/XmingProvider.vb +++ b/mRemoteV1/Config/Putty/XmingProvider.vb @@ -2,30 +2,13 @@ Imports mRemoteNG.App Imports mRemoteNG.Messages Imports mRemoteNG.Connection.Protocol +Imports System.Text.RegularExpressions Namespace Config.Putty Public Class XmingProvider Inherits Provider - Private Shared _eventWatcher As FileSystemWatcher - - Private Shared Function GetPuttyConfPath() As String - Dim puttyPath As String - If My.Settings.UseCustomPuttyPath Then - puttyPath = My.Settings.CustomPuttyPath - Else - puttyPath = Info.General.PuttyPath - End If - Return Path.Combine(Path.GetDirectoryName(puttyPath), "putty.conf") - End Function - - Private Shared Function GetSessionsFolderPath() As String - Dim puttyConfPath As String = GetPuttyConfPath() - Dim sessionFileReader As New PuttyConfFileReader(puttyConfPath) - Dim basePath As String = Environment.ExpandEnvironmentVariables(sessionFileReader.GetValue("sshk&sess")) - Return Path.Combine(basePath, "sessions") - End Function - +#Region "Public Methods" Public Overrides Function GetSessionNames(Optional ByVal raw As Boolean = False) As String() Dim sessionsFolderPath As String = GetSessionsFolderPath() If Not Directory.Exists(sessionsFolderPath) Then Return New String() {} @@ -40,17 +23,33 @@ Namespace Config.Putty End If Next - If sessionNames.Contains("Default%20Settings") Then ' Do not localize - sessionNames.Remove("Default%20Settings") - End If - If sessionNames.Contains("Default Settings") Then - sessionNames.Remove("Default Settings") + If raw Then + If Not sessionNames.Contains("Default%20Settings") Then ' Do not localize + sessionNames.Insert(0, "Default%20Settings") + End If + Else + If Not sessionNames.Contains("Default Settings") Then + sessionNames.Insert(0, "Default Settings") + End If End If + Dim registrySessionNames As New List(Of String) + For Each sessionName As String In RegistryProvider.GetSessionNames(raw) + registrySessionNames.Add(String.Format(RegistrySessionNameFormat, sessionName)) + Next + + sessionNames.AddRange(registrySessionNames) + sessionNames.Sort() + Return sessionNames.ToArray() End Function Public Overrides Function GetSession(ByVal sessionName As String) As Connection.PuttySession.Info + Dim registrySessionName As String = GetRegistrySessionName(sessionName) + If Not String.IsNullOrEmpty(registrySessionName) Then + Return ModifyRegistrySessionInfo(RegistryProvider.GetSession(registrySessionName)) + End If + Dim sessionsFolderPath As String = GetSessionsFolderPath() If Not Directory.Exists(sessionsFolderPath) Then Return Nothing @@ -99,6 +98,9 @@ Namespace Config.Putty End Function Public Overrides Sub StartWatcher() + RegistryProvider.StartWatcher() + AddHandler RegistryProvider.SessionChanged, AddressOf OnRegistrySessionChanged + If _eventWatcher IsNot Nothing Then Return Try @@ -115,16 +117,70 @@ Namespace Config.Putty End Sub Public Overrides Sub StopWatcher() + RegistryProvider.StopWatcher() + RemoveHandler RegistryProvider.SessionChanged, AddressOf OnRegistrySessionChanged + If _eventWatcher Is Nothing Then Return _eventWatcher.EnableRaisingEvents = False _eventWatcher.Dispose() _eventWatcher = Nothing End Sub +#End Region + +#Region "Private Fields" + Private Const RegistrySessionNameFormat As String = "{0} [registry]" + Private Const RegistrySessionNamePattern As String = "(.*)\ \[registry\]" + + Private Shared ReadOnly RegistryProvider As New RegistryProvider + Private Shared _eventWatcher As FileSystemWatcher +#End Region + +#Region "Private Methods" + Private Shared Function GetPuttyConfPath() As String + Dim puttyPath As String + If My.Settings.UseCustomPuttyPath Then + puttyPath = My.Settings.CustomPuttyPath + Else + puttyPath = Info.General.PuttyPath + End If + Return Path.Combine(Path.GetDirectoryName(puttyPath), "putty.conf") + End Function + + Private Shared Function GetSessionsFolderPath() As String + Dim puttyConfPath As String = GetPuttyConfPath() + Dim sessionFileReader As New PuttyConfFileReader(puttyConfPath) + Dim basePath As String = Environment.ExpandEnvironmentVariables(sessionFileReader.GetValue("sshk&sess")) + Return Path.Combine(basePath, "sessions") + End Function + + Private Shared Function GetRegistrySessionName(ByVal sessionName As String) As String + Dim regex As New Regex(RegistrySessionNamePattern) + + Dim matches As MatchCollection = regex.Matches(sessionName) + If matches.Count < 1 Then Return String.Empty + + Dim groups As GroupCollection = matches(0).Groups + If groups.Count < 1 Then Return String.Empty ' This should always include at least one item, but check anyway + + Return groups(1).Value + End Function + + Private Shared Function ModifyRegistrySessionInfo(ByVal sessionInfo As Connection.PuttySession.Info) As Connection.PuttySession.Info + sessionInfo.Name = String.Format(RegistrySessionNameFormat, sessionInfo.Name) + sessionInfo.PuttySession = String.Format(RegistrySessionNameFormat, sessionInfo.PuttySession) + Return sessionInfo + End Function Private Sub OnFileSystemEventArrived(ByVal sender As Object, ByVal e As FileSystemEventArgs) OnSessionChanged(New SessionChangedEventArgs()) End Sub + Private Sub OnRegistrySessionChanged(ByVal sender As Object, ByVal e As SessionChangedEventArgs) + OnSessionChanged(New SessionChangedEventArgs()) + End Sub +#End Region + +#Region "Private Classes" Private Class PuttyConfFileReader Public Sub New(ByVal puttyConfFile As String) _puttyConfFile = puttyConfFile @@ -198,5 +254,6 @@ Namespace Config.Putty Return _sessionInfo(setting) End Function End Class +#End Region End Class End Namespace diff --git a/mRemoteV1/mRemoteV1.vbproj b/mRemoteV1/mRemoteV1.vbproj index 047b85a2a..7792a424e 100644 --- a/mRemoteV1/mRemoteV1.vbproj +++ b/mRemoteV1/mRemoteV1.vbproj @@ -186,7 +186,6 @@ -