Answered Process Id and UserName

Hi Guys,

I want to control the number of connection of my user. Like one connection at the time or maybe more.

So I start to search a way to know all the process ID of the windows user session.

This is my code:

Code:
&GLOB TH32CS_SNAPPROCESS 2
 
PROCEDURE CreateToolhelp32Snapshot EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER dwFlags           AS LONG.
  DEFINE INPUT  PARAMETER th32ProcessId     AS LONG.
  DEFINE RETURN PARAMETER hSnapShot         AS LONG.
END PROCEDURE.
 
PROCEDURE Process32First EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER hSnapShot         AS LONG.
  DEFINE INPUT  PARAMETER lpProcessEntry32  AS MEMPTR.
  DEFINE RETURN PARAMETER ReturnValue       AS LONG.
END PROCEDURE.
 
PROCEDURE Process32Next EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER hSnapShot         AS LONG.
  DEFINE INPUT  PARAMETER lpProcessEntry32  AS MEMPTR.
  DEFINE RETURN PARAMETER ReturnValue       AS LONG.
END PROCEDURE.
 
PROCEDURE CloseHandle EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER hObject           AS LONG.
  DEFINE RETURN PARAMETER ReturnValue       AS LONG.
END PROCEDURE.


RUN ListProcesses.
 
PROCEDURE ListProcesses:
 
    DEFINE VARIABLE hSnapShot   AS INTEGER   NO-UNDO.
    DEFINE VARIABLE lpPE        AS MEMPTR    NO-UNDO. /* PROCESSENTRY32 structure */
    DEFINE VARIABLE ReturnValue AS INTEGER   NO-UNDO.
    DEFINE VARIABLE list        AS CHARACTER NO-UNDO INITIAL "Process-List:".

 
 
    /* Create and open SnapShot-list */
    RUN CreateToolhelp32Snapshot({&TH32CS_SNAPPROCESS},
                                 0,
                                 OUTPUT hSnapShot).
    IF hSnapShot = -1 THEN RETURN.
 
    /* init buffer for lpPE */
    SET-SIZE(lpPE)    = 336.
    PUT-LONG(lpPE, 1) = GET-SIZE(lpPE).

    
 
    /* Cycle thru process-records */
    RUN Process32First(hSnapShot,
                       lpPE,
                       OUTPUT ReturnValue).
    DO WHILE ReturnValue NE 0:

      IF GET-STRING(lpPE, 37) MATCHES "*prowin32.exe*" THEN DO:
        
          MESSAGE GET-STRING(lpPE, 1)
              VIEW-AS ALERT-BOX INFO BUTTONS OK.
       list = list + "~n".
 
       /* show process identifier (pid): */
       list = list + STRING(GET-LONG(lpPE, 9)) + " ".
 
       /* show path and filename of executable: */
       list = list + GET-STRING(lpPE, 37).
      END.

       RUN Process32Next(hSnapShot,
                         lpPE,
                         OUTPUT ReturnValue).
    END.
 
    /* Close SnapShot-list */
    RUN CloseHandle(hSnapShot, OUTPUT ReturnValue).
 
    MESSAGE list
        VIEW-AS ALERT-BOX INFO BUTTONS OK.
 
END PROCEDURE.

I found it there : Get a list of processes (Windows 95/98/2000) | The OpenEdge Hive .

But I want to know wich windows user is the owner of the PID .

Do you know something ?
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
I want to control the number of connection of my user. Like one connection at the time or maybe more.

So I start to search a way to know all the process ID of the windows user session.

I'm not sure that this is the correct approach. What is a PID going to tell you, once you know what it is? Windows doesn't know anything about your application users.

If we assume all of your users are authenticated and have unique IDs in the database (i.e. no one connects as blank user, and you don't have everyone logging in as "genericuser"), you can look at the _connect VST.

Here is a possible high-level process:
  • User runs application shortcut.
  • User successfully authenticates as "robf".
  • User's session reads _connect records to see if any other users are already authenticated as "robf".
    • If not, session is allowed to proceed.
    • If so, session throws an appropriate error message and exits.
 
Hi, In fact I need to add more information.

1. My user are in virtualize machine so I can have 20, more progress PID runing on a same machine
2. I don't have access to the login procedure
3. If I run a test before executing the launcher I don't want to be connected to the database in case of a problem and overcharge the number of connexion

I was going on the PID but it's more like the followinf info : PID owner, PID, Process Name ?
 

TomBascom

Curmudgeon
Using the Windows PID is doomed to failure. Multiple different users can have the same PID because they are all running on individual PCs. If you think you are protected because they happen to be running on a terminal server what happens when a second terminal server gets added?

Rob's solution using _Connect is better.

Another solution is to use a login control table within the application. This might be "better" because you can store more interesting information about the user.

If you go the route of an application table you also have an opportunity to exercise one of the very few legitimate ways to use a SHARE-LOCK. Basically on login the user tries for an exclusive lock of the record. If successful they then allow it to downgrade to SHARE-LOCK. A second instance of that user will be unable to get the EXCLUSIVE-LOCK until the first user logs out (or crashes). If the db is shutdown (or crashes) it all cleans itself up automatically. It is actually kind of elegant.
 
I like The idea. But I can't work on the login process because it's a compiled program and I don't have the source.

So the better way for all you is to do something like a launcher to test before even launching the application ?

Best Regards,
 

TomBascom

Curmudgeon
Actually I'd like to backup a few steps and ask:

Why?

Why do you want to limit the number of sessions that a user opens? What is the point? What do you hope to gain as a result?

If users are opening multiple sessions they almost always have good reasons for doing so. Often those good reasons have to do with inadequacies of the application that could be better addressed by fixing the actual problems rather than by limiting user sessions.

If your best excuse for limiting sessions is that you are vaguely worried about "resource consumption" then I suggest that you need some specific data about what specific resources are being limited and what is driving those limits. I doubt that "number of user sessions" will rank very high on the true root cause list.
 
The main issue is not for the office user but for our production.

We have a big hardware issue in our production area : Dust. The dust go under the key of keyboards and result in to launch many session (20, 30, 60) depends on the day or the user just want to start one session at time. This is why we wan't to control the number of connexion fo our users.

Today we use a vbscript but sometimes it's goes sideways and overcharge our virtual computer so we want a more cleaner way to do it.
 

Cringer

ProgressTalk.com Moderator
Staff member
Wouldn't it be better (and probably cheaper) to invest in dust-proof keyboards?!
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
If you go the route of an application table you also have an opportunity to exercise one of the very few legitimate ways to use a SHARE-LOCK. Basically on login the user tries for an exclusive lock of the record. If successful they then allow it to downgrade to SHARE-LOCK. A second instance of that user will be unable to get the EXCLUSIVE-LOCK until the first user logs out (or crashes). If the db is shutdown (or crashes) it all cleans itself up automatically. It is actually kind of elegant.

We do this in our third-party integration. External interfaces that should have only one running instance acquire an exclusive lock on a control table record then downgrade it to shared. It works well.

(But make sure you scope it properly and don't turn the whole session into a transaction. ;) )
 

Osborne

Active Member
The lock solution outlined by Tom and Rob is the best way to do this.

If you have to use a different option I suppose using Win32_Process via .NET may give some information:
Code:
DEFINE VARIABLE oEnvVar AS System.Management.ManagementObject NO-UNDO.
DEFINE VARIABLE oEnumeration AS System.Management.ManagementObjectCollection+ManagementObjectEnumerator NO-UNDO.
DEFINE VARIABLE oSearcher AS System.Management.ManagementObjectSearcher NO-UNDO.
DEFINE VARIABLE oQuery AS System.Management.ObjectQuery NO-UNDO.

oQuery = NEW System.Management.ObjectQuery("Select * From Win32_Process where Name = 'prowin32.exe'").
oSearcher = NEW System.Management.ManagementObjectSearcher(oQuery).
oEnumeration = oSearcher:Get():GetEnumerator().

DO WHILE oEnumeration:MoveNext() = TRUE:
   oEnvVar = CAST(oEnumeration:Current,System.Management.ManagementObject).
   DEFINE VARIABLE oSystemObject AS "System.Object[]" NO-UNDO.
   oSystemObject = NEW "System.Object[]" (2).
   oEnvVar:InvokeMethod("GetOwner",oSystemObject).
   MESSAGE "Program: " oEnvVar:Item["Name"]:ToString() SKIP
           "User Name: " oSystemObject:GetValue(0)
           VIEW-AS ALERT-BOX.
END.
System.Management has to be added to assemblies.
 

TomBascom

Curmudgeon
Perhaps I lack imagination but the only way that I can see that dust or a tool lying on a keyboard could result in multiple sessions would be if there is no login authentication at all.

It also seems kind of odd that you do not have access to the login code yet you know it is complex. You apparently have free access to the rest of the code? So why is the login code not available?
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
If you have to use a different option I suppose using Win32_Process via .NET may give some information:

This breaks if:
  • they switch to a 64-bit runtime (prowin.exe);
  • they happen to run some other unrelated OE GUI application on the same system;
  • some other vendor happens to choose "prowin32.exe" as an executable name, and it runs on this system.
 
Perhaps I lack imagination but the only way that I can see that dust or a tool lying on a keyboard could result in multiple sessions would be if there is no login authentication at all.

It also seems kind of odd that you do not have access to the login code yet you know it is complex. You apparently have free access to the rest of the code? So why is the login code not available?

Yes in Fact for this one we have that we called a "small menu" this version auto-log to the db for our operator in the production. But for this one we already have the solution to control the number of same user connected to the DB with VST _Connect.

The issue we have for our standard erp application, is that each time you launch a prowin32, this app take resources. If we ware on physical machine it would not impact the production. But all our production is on virtual machine. So if one user launch 20 prowin32 -> 1 prowin32 take 36Mo of ram so the user take 20*36 = 720 Mo of Ram and we don't want that ......


And the fact we can't have access to the source of our loggin interface is that we doesn't own the source code. We have buyed our main erp application. And we develloped all the specif we need. And so in the loggin source code there is the identification of the licence key of our software distributor.
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
If we ware on physical machine it would not impact the production. But all our production is on virtual machine.
I don't understand this. Resource utilization doesn't affect physical machines, only virtual ones?
So if one user launch 20 prowin32 -> 1 prowin32 take 36Mo of ram so the user take 20*36 = 720 Mo of Ram and we don't want that
In general, more processes will mean more resource consumption but the math is not so straightfoward. While each process has its own private memory (e.g. buffer contents, heap, thread stacks, etc.), it also has shareable memory, like executable code. So, some pages of prowin32.exe, prow32.dll, etc. may be mapped into the virtual memory address spaces of two different prowin32.exe processes. Even if those pages are in the working sets of both processes (i.e. physically resident), there aren't two copies of each in RAM. The OS loads one copy of those pages and each process has references to them.

How much RAM a process actually uses can be impacted by a lot of factors (not just its virtual memory size) and is ultimately decided by the memory manager.
 
I don't understand this. Resource utilization doesn't affect physical machines, only virtual ones?

IF a memory of a physical machine is full, the only impact is herself. But on virtual one if one user take 50% of the memory, the 39 others users are impacted and so 25% of our production... that's why.


In general, more processes will mean more resource consumption but the math is not so straightfoward. While each process has its own private memory (e.g. buffer contents, heap, thread stacks, etc.), it also has shareable memory, like executable code. So, some pages of prowin32.exe, prow32.dll, etc. may be mapped into the virtual memory address spaces of two different prowin32.exe processes. Even if those pages are in the working sets of both processes (i.e. physically resident), there aren't two copies of each in RAM. The OS loads one copy of those pages and each process has references to them.

How much RAM a process actually uses can be impacted by a lot of factors (not just its virtual memory size) and is ultimately decided by the memory manager.

I know it's a simple explanation.


But for us we wan't to limit the number of connexion for our production session.
 
Top