Single instance app StartupNextInstance

  • Thread starter Thread starter QSIDeveloper
  • Start date Start date
Q

QSIDeveloper

I am using the My.Application.StartupNextInstance Event from
Microsoft.VisualBasic.ApplicationServices to facilitate a single instance app
in a C# application. I have an issue where we need to have the app run from
different folder where each folder will represent a separate instance. For
example if I have app.exe in folder one and app.exe in folder two. The
app.exe in folder one is to communicated with URL server1 and the app in
folder two is to communicated with URL server2 both apps need to be single
instance and stay resident but recognize what folder they were launched from.
I have found that if I change the GUID in assembly info a build time then
this scheme works but this is not a workable solution. So two questions;
1)What are teh flag(s) that are used to decide that an exe is the same as the
one already running, is it just the GUID or are there other flags? 2) Is
there a way I can get the same exe running from two (or more) different
directories to run separate single instances?
 
Hi John,

Let me answer your questions:

1) What are the flag(s) that are used to decide that an exe is the same as
the one already running, is it just the GUID or are there other flags?

In Microsoft.VisualBasic.dll 8.0, the *Application Instance ID* is composed
of:

i. Assembly Typelib GUID
ii. Assembly Major Version Number
iii.Assembly Minor Version Number

The implementing code looks like this:

private string GetApplicationInstanceID(Assembly Entry)
{
PermissionSet set = new PermissionSet(PermissionState.None);
set.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
set.AddPermission(new
SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
set.Assert();
Guid typeLibGuidForAssembly = Marshal.GetTypeLibGuidForAssembly(Entry);
string[] strArray =
Entry.GetName().Version.ToString().Split(Conversions.ToCharArrayRankOne(".")
);
PermissionSet.RevertAssert();
return (typeLibGuidForAssembly.ToString() + strArray[0] + "." +
strArray[1]);
}

2) Is there a way I can get the same exe running from two (or more)
different directories to run separate single instances?

Yes. But not using the VisualBasic.ApplicationServices - because the logic
has been burnt into the code, as explained in answer 1).

In your case, you may consider implementing your own single instance
feature using Mutex. We can add Assembly Location info into the mutex name
so instances from different locations will not be considered as the same
app.
Here is a piece of sample code to proof the concept:

static void Main(string[] args)
{
bool mutexWasCreated = false;
string mutexName;
string asmLocHash;
Assembly execAsm = Assembly.GetExecutingAssembly();
SHA1Managed sha = new SHA1Managed();
Mutex m;

// The mutext name cannot be longer than 260 characters.
// So we use the hash value of the location instead of the real path,
// in case the Location string is too long for a mutex name.
asmLocHash =
Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(execAsm.Locati
on)));
// mutexName = GUID + Ver Major.Minor + Asm Location Hash
mutexName = Marshal.GetTypeLibGuidForAssembly(execAsm).ToString() +
string.Format("{0}.{1}", execAsm.GetName().Version.Major,
execAsm.GetName().Version.Minor) +
asmLocHash;

try
{
m = Mutex.OpenExisting(mutexName);
}
catch (WaitHandleCannotBeOpenedException)
{
m = new Mutex(true, mutexName, out mutexWasCreated);
}

if (mutexWasCreated)
{
Console.WriteLine("This is the first instance.\r\nWorking...");
Console.ReadLine();
}
else
{
Console.WriteLine("This is not the first instance.\r\nExiting...");
Console.ReadLine();
}

m.Close();
}

If you have any further questions regarding this issue, please feel free to
post here.

Regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
We have code similar to that now.
What is the best way to hand off the args[] to the existing instance in c#?


"Jie Wang [MSFT]" said:
Hi John,

Let me answer your questions:

1) What are the flag(s) that are used to decide that an exe is the same as
the one already running, is it just the GUID or are there other flags?

In Microsoft.VisualBasic.dll 8.0, the *Application Instance ID* is composed
of:

i. Assembly Typelib GUID
ii. Assembly Major Version Number
iii.Assembly Minor Version Number

The implementing code looks like this:

private string GetApplicationInstanceID(Assembly Entry)
{
PermissionSet set = new PermissionSet(PermissionState.None);
set.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
set.AddPermission(new
SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
set.Assert();
Guid typeLibGuidForAssembly = Marshal.GetTypeLibGuidForAssembly(Entry);
string[] strArray =
Entry.GetName().Version.ToString().Split(Conversions.ToCharArrayRankOne(".")
);
PermissionSet.RevertAssert();
return (typeLibGuidForAssembly.ToString() + strArray[0] + "." +
strArray[1]);
}

2) Is there a way I can get the same exe running from two (or more)
different directories to run separate single instances?

Yes. But not using the VisualBasic.ApplicationServices - because the logic
has been burnt into the code, as explained in answer 1).

In your case, you may consider implementing your own single instance
feature using Mutex. We can add Assembly Location info into the mutex name
so instances from different locations will not be considered as the same
app.
Here is a piece of sample code to proof the concept:

static void Main(string[] args)
{
bool mutexWasCreated = false;
string mutexName;
string asmLocHash;
Assembly execAsm = Assembly.GetExecutingAssembly();
SHA1Managed sha = new SHA1Managed();
Mutex m;

// The mutext name cannot be longer than 260 characters.
// So we use the hash value of the location instead of the real path,
// in case the Location string is too long for a mutex name.
asmLocHash =
Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(execAsm.Locati
on)));
// mutexName = GUID + Ver Major.Minor + Asm Location Hash
mutexName = Marshal.GetTypeLibGuidForAssembly(execAsm).ToString() +
string.Format("{0}.{1}", execAsm.GetName().Version.Major,
execAsm.GetName().Version.Minor) +
asmLocHash;

try
{
m = Mutex.OpenExisting(mutexName);
}
catch (WaitHandleCannotBeOpenedException)
{
m = new Mutex(true, mutexName, out mutexWasCreated);
}

if (mutexWasCreated)
{
Console.WriteLine("This is the first instance.\r\nWorking...");
Console.ReadLine();
}
else
{
Console.WriteLine("This is not the first instance.\r\nExiting...");
Console.ReadLine();
}

m.Close();
}

If you have any further questions regarding this issue, please feel free to
post here.

Regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi John,

I recommend using remoting.

Here is how the VB.NET does it:

1. The first instance create an instance of the RemoteCommunicator class
(inherits MarshalByRefObject) and start listening on a TCP channel. The
port number is randomly selected from available ports. The URI contains the
unique App Instance ID.

2. Then the first instance writes the URL (made from the URI in step one)
to a named file mapping using the CreateFileMapping function (kernel32).
The name of the mapping object is the App Instance ID.

For the later instances, they will:

3. Read the URL info from the name mapping.

4. Connect to the RemoteCommunicator available on the URL (from the first
instance).

5. Call the RunNextInstance method of the RemoteCommunicator and hand over
the command line arguments.

I strongly recommend reading the code of the
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run
method using .NET Reflector or some other similar tools to see the actual
implementation. That's a nice sample to follow.

Hope this helps. And again, if there is anything I can help, just let me
know.

Have a nice weekend!

Regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi John,

How's going with this issue?

I know it need some efforts to implement such a feature, if you have any
follow up questions, please feel free to let me know.

Regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top