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..5a47f81fb98 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
@@ -354,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
@@ -1006,28 +1008,35 @@ 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 guidAttrib As GuidAttribute = Entry.GetCustomAttribute(Of GuidAttribute)()
-
- If guidAttrib IsNot Nothing Then
-
- Dim version As Version = Entry.GetName.Version
-
+ 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 $"{guidAttrib.Value}{version.Major}.{version.Minor}"
+ Return $"{pathGuid}-{guidAttribute.Value}{version.Major}.{version.Minor}-{currentUserSID}"
Else
- Return guidAttrib.Value
+ Return $"{pathGuid}-{guidAttribute.Value}-{currentUserSID}"
End If
End If
- Return Entry.ManifestModule.ModuleVersionId.ToString()
+ 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
+ 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
End Namespace
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..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,15 +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 expectedId = assembly.ManifestModule.ModuleVersionId.ToString();
+ string currentUserSID = System.Security.Principal.WindowsIdentity.GetCurrent().User.Value;
+ 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 });
@@ -32,27 +39,41 @@ private static string GetUniqueIDFromAssembly(string guid, Version version)
AssemblyBuilderAccess.RunAndCollect,
new[] { attributeBuilder });
assemblyBuilder.DefineDynamicModule(Guid.NewGuid().ToString());
- return GetAppID(assemblyBuilder);
+ return assemblyBuilder;
}
[Fact]
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;
+ 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]
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;
+ 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]
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;
+ var assembly = CreateDynamicAssembly(guid, null);
+ string location = assembly.Location;
+ Guid expectedPathGuid = GetFilePathAsGuid(location);
+ Assert.Equal($"{expectedPathGuid}-{guid}0.0-{currentUserSID}", GetAppID(assembly));
}
}