From 22668d1e618d4e3d597c55e424ce7f612d91fa43 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Wed, 24 Apr 2024 08:41:08 +1000 Subject: [PATCH 1/6] Fixes #3715 - Add currentUserSID to GetApplicationInstanceID for use in TryCreatePipeServer to avoid system wide blocking. Used in conjunction with PipeOptions.CurrentUserOnly --- .../WindowsFormsApplicationBase.vb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb index f03e1f494e7..5f10f4c0bb1 100644 --- a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb +++ b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb @@ -1006,28 +1006,26 @@ Namespace Microsoft.VisualBasic.ApplicationServices ''' ''' Generates the name for the remote singleton that we use to channel multiple instances - ''' to the same application model thread. + ''' to the same application model thread for the current user. ''' ''' A string unique to the application that should be the same for versions of ''' the application that have the same Major and Minor Version Number ''' ''' If GUID Attribute does not exist fall back to unique ModuleVersionId Private Shared Function GetApplicationInstanceID(ByVal Entry As Assembly) As String + Dim guidAttribute As GuidAttribute = Entry.GetCustomAttribute(Of GuidAttribute)() + Dim currentUserSID As String = Principal.WindowsIdentity.GetCurrent().User.Value - Dim guidAttrib As GuidAttribute = Entry.GetCustomAttribute(Of GuidAttribute)() - - If guidAttrib IsNot Nothing Then - + If guidAttribute IsNot Nothing Then Dim version As Version = Entry.GetName.Version - If version IsNot Nothing Then - Return $"{guidAttrib.Value}{version.Major}.{version.Minor}" + Return $"{guidAttribute.Value}{version.Major}.{version.Minor}-{currentUserSID}" Else - Return guidAttrib.Value + Return $"{guidAttribute.Value}-{currentUserSID}" End If End If - Return Entry.ManifestModule.ModuleVersionId.ToString() + Return $"{Entry.ManifestModule.ModuleVersionId}-{currentUserSID}" End Function End Class End Namespace From 1edb42ecbfbb9526fbea030747c64dc1884265d5 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Wed, 24 Apr 2024 10:52:24 +1000 Subject: [PATCH 2/6] Fix tests --- .../WindowsFormsApplicationBaseTests.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs b/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs index 8ee2c982c4f..d0ec8dc7afb 100644 --- a/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs +++ b/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs @@ -19,7 +19,8 @@ private static string GetAppID(Assembly assembly) public void GetApplicationInstanceID() { var assembly = typeof(WindowsFormsApplicationBaseTests).Assembly; - string expectedId = assembly.ManifestModule.ModuleVersionId.ToString(); + string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; + string expectedId = $"{assembly.ManifestModule.ModuleVersionId}-{currentUserSID}"; Assert.Equal(expectedId, GetAppID(assembly)); } @@ -39,20 +40,23 @@ private static string GetUniqueIDFromAssembly(string guid, Version version) public void GetApplicationInstanceID_GuidAttribute() { string guid = Guid.NewGuid().ToString(); - Assert.Equal($"{guid}1.2", GetUniqueIDFromAssembly(guid, new Version(1, 2, 3, 4))); + string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; + Assert.Equal($"{guid}1.2-{currentUserSID}", GetUniqueIDFromAssembly(guid, new Version(1, 2, 3, 4))); } [Fact] public void GetApplicationInstanceID_GuidAttributeNewVersion() { string guid = Guid.NewGuid().ToString(); - Assert.Equal($"{guid}0.0", GetUniqueIDFromAssembly(guid, new Version())); + string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; + Assert.Equal($"{guid}0.0-{currentUserSID}", GetUniqueIDFromAssembly(guid, new Version())); } [Fact] public void GetApplicationInstanceID_GuidAttributeNullVersion() { string guid = Guid.NewGuid().ToString(); - Assert.Equal($"{guid}0.0", GetUniqueIDFromAssembly(guid, version: null)); + string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; + Assert.Equal($"{guid}0.0-{currentUserSID}", GetUniqueIDFromAssembly(guid, version: null)); } } From bb2322e5e7169776f501cab657bb2de1408f219e Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:57:51 +1000 Subject: [PATCH 3/6] Fix Code style --- .../ApplicationServices/WindowsFormsApplicationBase.vb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb index 5f10f4c0bb1..2d7b6e0fd10 100644 --- a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb +++ b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb @@ -1012,12 +1012,12 @@ Namespace Microsoft.VisualBasic.ApplicationServices ''' the application that have the same Major and Minor Version Number ''' ''' If GUID Attribute does not exist fall back to unique ModuleVersionId - Private Shared Function GetApplicationInstanceID(ByVal Entry As Assembly) As String - Dim guidAttribute As GuidAttribute = Entry.GetCustomAttribute(Of GuidAttribute)() + Private Shared Function GetApplicationInstanceID(entry As Assembly) As String + Dim guidAttribute As GuidAttribute = entry.GetCustomAttribute(Of GuidAttribute)() Dim currentUserSID As String = Principal.WindowsIdentity.GetCurrent().User.Value If guidAttribute IsNot Nothing Then - Dim version As Version = Entry.GetName.Version + Dim version As Version = entry.GetName.Version If version IsNot Nothing Then Return $"{guidAttribute.Value}{version.Major}.{version.Minor}-{currentUserSID}" Else @@ -1025,7 +1025,7 @@ Namespace Microsoft.VisualBasic.ApplicationServices End If End If - Return $"{Entry.ManifestModule.ModuleVersionId}-{currentUserSID}" + Return $"{entry.ManifestModule.ModuleVersionId}-{currentUserSID}" End Function End Class End Namespace From 083c991a7e6f9611a819e4f406c75a2c605dde79 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Tue, 14 May 2024 09:37:46 +1000 Subject: [PATCH 4/6] Add fix for #11365 --- .../WindowsFormsApplicationBase.vb | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb index 2d7b6e0fd10..5e99c3c8c1c 100644 --- a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb +++ b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb @@ -11,6 +11,8 @@ Imports System.IO.Pipes Imports System.Reflection Imports System.Runtime.InteropServices Imports System.Security +Imports System.Security.Cryptography +Imports System.Text Imports System.Threading Imports System.Windows.Forms Imports Microsoft.VisualBasic.CompilerServices @@ -1015,17 +1017,28 @@ Namespace Microsoft.VisualBasic.ApplicationServices Private Shared Function GetApplicationInstanceID(entry As Assembly) As String Dim guidAttribute As GuidAttribute = entry.GetCustomAttribute(Of GuidAttribute)() Dim currentUserSID As String = Principal.WindowsIdentity.GetCurrent().User.Value - + Dim location As String = entry.Location + Dim pathGuid As Guid = GetFilePathAsGuid(location) If guidAttribute IsNot Nothing Then Dim version As Version = entry.GetName.Version If version IsNot Nothing Then - Return $"{guidAttribute.Value}{version.Major}.{version.Minor}-{currentUserSID}" + Return $"{pathGuid}-{guidAttribute.Value}{version.Major}.{version.Minor}-{currentUserSID}" Else - Return $"{guidAttribute.Value}-{currentUserSID}" + Return $"{pathGuid}-{guidAttribute.Value}-{currentUserSID}" End If End If - Return $"{entry.ManifestModule.ModuleVersionId}-{currentUserSID}" + Return $"{pathGuid}-{entry.ManifestModule.ModuleVersionId}-{currentUserSID}" + End Function + +#Disable Warning CA5351 ' We want speed over collision resistance. + Private Shared Function GetFilePathAsGuid(filePath As String) As Guid + Using md5 As MD5 = MD5.Create() + Dim filePathBytes As Byte() = Encoding.UTF8.GetBytes(filePath) + Dim hashBytes As Byte() = MD5.HashData(filePathBytes) + Return New Guid(hashBytes) + End Using End Function +#Enable Warning CA5351 End Class End Namespace From c91531d269cdbc98f580cfda3dc1735b6cd3c330 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Tue, 14 May 2024 10:53:11 +1000 Subject: [PATCH 5/6] Small refactor and fix tests --- .../WindowsFormsApplicationBase.vb | 8 ++--- .../WindowsFormsApplicationBaseTests.cs | 29 +++++++++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb index 5e99c3c8c1c..b2b63107252 100644 --- a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb +++ b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb @@ -1033,11 +1033,9 @@ Namespace Microsoft.VisualBasic.ApplicationServices #Disable Warning CA5351 ' We want speed over collision resistance. Private Shared Function GetFilePathAsGuid(filePath As String) As Guid - Using md5 As MD5 = MD5.Create() - Dim filePathBytes As Byte() = Encoding.UTF8.GetBytes(filePath) - Dim hashBytes As Byte() = MD5.HashData(filePathBytes) - Return New Guid(hashBytes) - End Using + Dim filePathBytes As Byte() = Encoding.UTF8.GetBytes(filePath) + Dim hashBytes As Byte() = MD5.HashData(filePathBytes) + Return New Guid(hashBytes) End Function #Enable Warning CA5351 End Class diff --git a/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs b/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs index d0ec8dc7afb..392d80cc100 100644 --- a/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs +++ b/src/Microsoft.VisualBasic/tests/UnitTests/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBaseTests.cs @@ -15,16 +15,22 @@ private static string GetAppID(Assembly assembly) return testAccessor.Dynamic.GetApplicationInstanceID(assembly); } + private static Guid GetFilePathAsGuid(string filePath) + { + var testAccessor = typeof(WindowsFormsApplicationBase).TestAccessor(); + return testAccessor.Dynamic.GetFilePathAsGuid(filePath); + } + [Fact] public void GetApplicationInstanceID() { var assembly = typeof(WindowsFormsApplicationBaseTests).Assembly; string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; - string expectedId = $"{assembly.ManifestModule.ModuleVersionId}-{currentUserSID}"; + string expectedId = $"{GetFilePathAsGuid(assembly.Location)}-{assembly.ManifestModule.ModuleVersionId}-{currentUserSID}"; Assert.Equal(expectedId, GetAppID(assembly)); } - private static string GetUniqueIDFromAssembly(string guid, Version version) + private static Assembly CreateDynamicAssembly(string guid, Version version) { CustomAttributeBuilder attributeBuilder = new( typeof(GuidAttribute).GetConstructor([typeof(string)]), new[] { guid }); @@ -33,7 +39,7 @@ private static string GetUniqueIDFromAssembly(string guid, Version version) AssemblyBuilderAccess.RunAndCollect, new[] { attributeBuilder }); assemblyBuilder.DefineDynamicModule(Guid.NewGuid().ToString()); - return GetAppID(assemblyBuilder); + return assemblyBuilder; } [Fact] @@ -41,7 +47,11 @@ public void GetApplicationInstanceID_GuidAttribute() { string guid = Guid.NewGuid().ToString(); string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; - Assert.Equal($"{guid}1.2-{currentUserSID}", GetUniqueIDFromAssembly(guid, new Version(1, 2, 3, 4))); + Version version = new Version(1, 2, 3, 4); + var assembly = CreateDynamicAssembly(guid, version); + string location = assembly.Location; + Guid expectedPathGuid = GetFilePathAsGuid(location); + Assert.Equal($"{expectedPathGuid}-{guid}{version.Major}.{version.Minor}-{currentUserSID}", GetAppID(assembly)); } [Fact] @@ -49,7 +59,11 @@ public void GetApplicationInstanceID_GuidAttributeNewVersion() { string guid = Guid.NewGuid().ToString(); string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; - Assert.Equal($"{guid}0.0-{currentUserSID}", GetUniqueIDFromAssembly(guid, new Version())); + Version version = new Version(); + var assembly = CreateDynamicAssembly(guid, version); + string location = assembly.Location; + Guid expectedPathGuid = GetFilePathAsGuid(location); + Assert.Equal($"{expectedPathGuid}-{guid}0.0-{currentUserSID}", GetAppID(assembly)); } [Fact] @@ -57,6 +71,9 @@ public void GetApplicationInstanceID_GuidAttributeNullVersion() { string guid = Guid.NewGuid().ToString(); string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value; - Assert.Equal($"{guid}0.0-{currentUserSID}", GetUniqueIDFromAssembly(guid, version: null)); + var assembly = CreateDynamicAssembly(guid, null); + string location = assembly.Location; + Guid expectedPathGuid = GetFilePathAsGuid(location); + Assert.Equal($"{expectedPathGuid}-{guid}0.0-{currentUserSID}", GetAppID(assembly)); } } From 03230e4dc4afc5f27d3f5bebe449f4efb3240403 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Wed, 15 May 2024 13:01:15 +1000 Subject: [PATCH 6/6] small change for debug --- .../ApplicationServices/WindowsFormsApplicationBase.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb index b2b63107252..5a47f81fb98 100644 --- a/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb +++ b/src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb @@ -356,7 +356,7 @@ Namespace Microsoft.VisualBasic.ApplicationServices Dim awaitable = SendSecondInstanceArgsAsync(ApplicationInstanceID, commandLine, cancellationToken:=tokenSource.Token).ConfigureAwait(False) awaitable.GetAwaiter().GetResult() Catch ex As Exception - Throw New CantStartSingleInstanceException() + Throw New CantStartSingleInstanceException($"{GetResourceString(SR.AppModel_SingleInstanceCantConnect)}: {ApplicationInstanceID}") End Try End If End If 'Single-Instance application