2

I have a Windows Forms application with C# code as shown below (targeting .NET framework 4).

On my developer workstation, this code works to prevent me from launching multiple instances of the program. However, QA has a Citrix test environment where each user is still able to launch multiple instances.

What can be done to prevent a given user from running multiple instances in Citrix?

[STAThread]
static void Main(string[] args)
{
    bool isFirstInstance;
    Mutex m = new Mutex(true, "[App name goes here] mutex", out isFirstInstance);

    if (isFirstInstance)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run();

        // Prevent the just-in-time (JIT) compiler from optimizing away our Mutex.
        // See: http://www.ai.uga.edu/mc/SingleInstance.html
        GC.KeepAlive(m);
    }
}

We want to limit the number of instances for technical reasons. The program uses self-hosted WCF to communicate with another process being run by the same user. We only want one instance of this program per user.

I don't know any details about the Citrix environment, but can inquire.

Thank you.

Spacewaster
  • 438
  • 3
  • 13
  • First [quicky google hit](http://support.citrix.com/proddocs/topic/xenapp5fp-w2k8/ps-sessions-pub-app-app-lmts-task-v2.html) scores. – Hans Passant Aug 05 '14 at 21:56
  • @nobugz: A rebuke gratefully taken. – Spacewaster Aug 06 '14 at 13:22
  • We are however not talking about a published application here. Our published application makes a system call, which launches the C# application, which then appears on the user's screen. We may want to publish it instead, and have the user manually launch it. Or use a global mutex as Bogdan proposed. – Spacewaster Aug 06 '14 at 13:25

3 Answers3

5

Using either a Local or Global scoped mutex can be appropriate depending on exactly what behaviour you want.

Using a mutex with "Local\" will ensure you only have one instance running per session. However it will still be possible for your user to launch multiple sessions on the same server (depending on how your Citrix environment is configured), and hence have multiple instances of your app running in different sessions.

If you want to be 100% each user only has once instance per server then you need to use a Global mutex. However you need to make sure you name your mutex with state specific to the user, e.g.

string globalMutexName = string.Format(
    CultureInfo.InvariantCulture,
    "Global\\AppName~{0}~{1}~some-unique-guid",
    Environment.UserDomainName,
    Environment.UserName);

_machineLocalAppInstanceMutex = new System.Threading.Mutex(true, globalMutexName, out mutexIsNew);

if (!mutexIsNew)
{
    Shutdown();
}

Also I'd make the mutex a member of a class, typically your main App/Form class rather than using GC.KeepAlive

donovan
  • 1,442
  • 9
  • 18
  • This answer nails the requirement, and the explanation and code both look good. I have therefore marked it as the answer. Unfortunately -- due to a Dilbert/CodingHorror working environment -- I won't be able to deploy and test it. Only QA and production have Citrix environments, and I no longer have authorization to release the change to QA. Such is life. Thank you! – Spacewaster Aug 21 '14 at 12:43
  • Your answer is exactly what I am looking for. You should probably set access rights as well https://stackoverflow.com/a/229567/2122718. What do you think about it? – marbel82 Mar 23 '23 at 11:59
2

Use a global mutex. The way your code is you can launch multiple instances of the program in different user sessions ... a global mutex will prevent that ...

Bogdan
  • 484
  • 2
  • 7
  • Perhaps I misunderstand, but wouldn't that reduce instances to one-per-machine (the machine being the Citrix server)? That would not meet the need of allowing one instance per user. – Spacewaster Aug 07 '14 at 13:00
  • Yeah, sorry, local mutex is what you need ... just put "Local\" in front of your name ... – Bogdan Aug 07 '14 at 22:41
0

The simplest and best solution for that is to use a mutex, here is the code for that.

static void Main(string[] args)
{
        String mutexName = "MyApplication" + 
        System.Security.Principal.WindowsIdentity.GetCurrent().User.AccountDomainSid;

        Boolean createdNew;

        Mutex mutex = new Mutex(true, mutexName, out createdNew);

        if (!createdNew)
        {
            //If createdNew is false that means an instance of application is already running for this   
            // user.
            //So in this case stop the application from executing.
            return;
        }
        Console.ReadKey();
}

You can find a detailed explanation at this link.

Yatharth Varshney
  • 1,973
  • 20
  • 22