0

In a terminal server situation I want to make sure only 1 instance of the application runs for each user.

What is the best way to do this?

Here is what i'm currently using but it seems like it isn't working as intended. I can't be 100% on that.

int SID = Process.GetCurrentProcess().SessionId;

Process current_process = Process.GetCurrentProcess();
int proc_count = 0;

foreach (Process p in Process.GetProcessesByName(current_process.ProcessName))
{
    proc_count++;
    if (p.SessionId.Equals(SID))
    {
        if (proc_count > 1)
        {
            Application.Current.Shutdown();
            return;
        }
    }
}

UPDATE To help clarify by the comments I have read I think it needs to be off the session ID because not all clients will follow one physical person per username and there for the user can be logged into the server multiple times.

Tsukasa
  • 6,342
  • 16
  • 64
  • 96

2 Answers2

1

The generally accepted way to do this is with a named mutex. By creating a named mutex you can determine if another instance is already running and shutdown the new instance.

This code should give you the desired result. All of this is assumed to be in the executable's main entry point.

bool createdMutex;
using (var processMutex = new System.Threading.Mutex(false, "Some name that is unique for the executable", out createdMutex)) {

   if (!createdMutex)
     ; // some other instance of the application is already running (or starting up). You may want to bring the other instance to foreground (assuming this is a GUI app)
   else 
   {
      // this is the process to actually run..
      // do application init stuff here
   }
}

Be warned, I typed the code here, so there may be syntax errors, typos and other accidental misdirection.

As request in the comments, here is some direction on choosing the name of the mutex:

If you want to limit the application to a single instance per terminal server session, then choose a mutex name that is unique to the application.

If you want to limit the application to a single instance per "user" within a terminal server session, choose a mutex name that is unique to the application and append the user's SID. WindowsIdentity.GetCurrent() will provide you with the SecurityIdentifier.

If you want to limit the application to a single instance per user, regardless of which terminal server session, choose a mutex name this is unique to the application with the user's SID included and prefix the name with "Global\".

If you want to limit the application to a single instance per server, choose a mutex name that is unique to the application and prefix with "Global\".

It is important to note that while a terminal server session is associated with a single user, that does not mean that all of the applications running in the session are associated with that user (consider "Run As" options).

William
  • 1,867
  • 11
  • 10
  • ""Some name that is unique for the executable"" should be unique per session "ZEEAppMutex_" would work. Here's a [link](http://dandar3.blogspot.ro/2010/03/single-instance-application-in-c-per.html) to help with that. Don't bother with GC.KeepAlive nonsense - just declare `private static Mutex mutex;` and you're good. – bkdc Oct 16 '13 at 18:50
  • 1
    I does not need to be, unless the name specifically indicates the global namespace, it will be put into the local namespace which is separate for each session. – William Oct 16 '13 at 18:51
  • you are correct - point taken! The other side of the coin is that you can have multiple terminal services sessions for the same user so...maybe the correct way to go is to have a mutex "Global\App_" if you want to ensure there's one app instance per user. – bkdc Oct 16 '13 at 19:06
  • 1
    Even then, the object namespace for Windows is still session based, not user based. So if you have multiple sessions even with the same user, the namespaces will be separate. Consider that within a single session, there may be any number of security tokens referencing different users. – William Oct 16 '13 at 19:09
  • 1
    I think I see what you are saying, if you truly want to limit the application to one per user, regardless of where that user is logged on to the machine then you would need to use the global namespace and create the mutex name using the SID of the process's token. Creating objects in the global namespace is a restricted operation though, so the user would need the appropriate permissions. – William Oct 16 '13 at 19:11
  • I interpreted his question as really being about the terminal server session, not the security token. – William Oct 16 '13 at 19:14
  • maybe the question/requirements need to be clarified by Tsukasa. So far it sounds to me like it's about users not sessions but you could go ahead and amend the response to cover both cases - a lot of users might appreciate that. – bkdc Oct 16 '13 at 19:17
  • It would be per session on the terminal server because someone could be using the same username twice. I don't like this but can't control the client from doing so. – Tsukasa Oct 16 '13 at 19:37
  • Thanks this helped solve my issue. The way I was running it I have to remove the using statement and place the mutex in the namespace. Then I just release it when the user quits the application. – Tsukasa Oct 16 '13 at 20:59
0

put a row in the database status = 1 or 0

1 means he's on

0 means he's off

if(status==0)
{
    //let him in
}
else
{
    //dont let him into the system
}

hopes this help with the structure/logic cause im not really very familiar with c# or .net

Dave Zych
  • 21,581
  • 7
  • 51
  • 66