Windows process info from Squeak

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Windows process info from Squeak

Valdas Bucinskas
Hello

Is there a way to get information about Windows XP processes from Squeak?
Smth like how much RAM is the process using? What is PID of the process? And
so on.
Any hints or workaraunds are very much welcome.

Best regards,
Valdas Bucinskas



Reply | Threaded
Open this post in threaded view
|

Re: Windows process info from Squeak

David T. Lewis
On Tue, Jan 31, 2006 at 02:34:25PM +0200, Valdas Bucinskas wrote:
> Hello
>
> Is there a way to get information about Windows XP processes from Squeak?
> Smth like how much RAM is the process using? What is PID of the process? And
> so on.
> Any hints or workaraunds are very much welcome.

See OSProcess and OSProcessPlugin on Squeak Map.

There is an old version of the plugin (Win32OSProcessPlugin.dll)
included in the OSProcess distribution, but you'll need to build
your own from source with VMMaker if you want the latest. The old
one will give you pid, and the more recent OSPP also gives the
environment, the current working directory, main thread ID, etc.
For the other things you might be interested in (memory use),
you might want to just use one of the existing OSPP primitives
as a template and put in whatever you want.

One word of warning, the latest SVN sources for Windows VM have
a security related "feature" that will break some of the OSPP
file-related functions. Let me know if this is a problem for
you and I'll try to come up with some sort of workaround. It's
not something I'm working on at the moment though.

Dave
 

Reply | Threaded
Open this post in threaded view
|

Re: Windows process info from Squeak

Boris.Gaertner
In reply to this post by Valdas Bucinskas
"Valdas Bucinskas" <[hidden email]> wrote:


> Hello
>
> Is there a way to get information about Windows XP processes from Squeak?
> Smth like how much RAM is the process using? What is PID of the process?
> And so on.
> Any hints or workaraunds are very much welcome.

The FFI interface is the framework that you can use to
program what you need.
(see also: http://minnow.cc.gatech.edu/squeak/1414
and http://minnow.cc.gatech.edu/squeak/2422)

To get the process id you have to do this:

1. In Win32Window, add this instance method:

apiGetCurrentProcessId
    <apicall: long 'GetCurrentProcessId' (void) module: 'kernel32.dll'>
    ^self externalCallFailed


2. Then try in a workspace:

Win32Window new apiGetCurrentProcessId

Getting a handle to the current process is not much more
difficult:

1. you have to add these instance methods:


apiGetCurrentProcess
    <apicall: Win32Handle 'GetCurrentProcess' (void) module: 'kernel32.dll'>
    ^self externalCallFailed

apiGetGuiResources: h type: int
    <apicall: long 'GetGuiResources' (Win32Handle long) module:
'user32.dll'>
    ^self externalCallFailed


2. Then you can try:

  | interface |  " gdi resources "
  interface := Win32Window new.
  interface apiGetGuiResources: interface apiGetCurrentProcess type: 0.

 | interface |  " user resources "
  interface := Win32Window new.
  interface apiGetGuiResources: interface apiGetCurrentProcess type: 1.


The attached change set contains these methods and a
class definition that is needed to obtain memory usage information.

Please have a look at the class comment for
Win32ProcessMemoryCounters to find out how you can
obtain memory information.

It is perhaps necessary to explicitely release (with free)
some of the Win32 structures, but I am not sure about
that. Comments are highly welcome.

Hope that helps a bit.
Boris











FFIWin.1.cs (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: Windows process info from Squeak

Valdas Bucinskas
In reply to this post by David T. Lewis
Thanks for the response.
For those who are interested, I have found another workaraound using
external utility Pslist (http://www.sysinternals.com/Utilities/PsList.html).
The code, returning how much RAM a Windows process is using, looks like this
(needs some refactoring though):
Prerequests: directory C:\Temp2 should exist, pslist.exe should be copied
into the directory that is listed in Windows Paths variable.

WindowsOS >> class
getInfo: aProcessName
        | path batch batchFile infoFromOutTxt numbers oc tmp filedir |
        path := 'C:\Temp2'.
        batch := 'pslist -m ' , aProcessName , ' >>' , path , '\out.txt'.
        filedir := FileDirectory new.
        filedir deleteFileNamed: path , '\out.txt' ifAbsent: nil.
        filedir deleteFileNamed: path , '\getProcessInfo.bat' ifAbsent: nil.
        [batchFile := (FileDirectory on: path)
                                fileNamed: 'getProcessInfo.bat'.
        batchFile nextPutAll: batch]
                ensure: [batchFile close].
        Win32Shell new shellOpen: path , '\' , 'getProcessInfo.bat'.
        [(filedir fileExists: path , '\out.txt') not]
                whileTrue: [(Delay forSeconds: 0.1) wait].
        infoFromOutTxt := (FileDirectory new oldFileNamed: path , '\out.txt')
upToEnd.
        numbers := (infoFromOutTxt copyFrom: (infoFromOutTxt findString:
aProcessName startingAt: 1)
                                        + aProcessName size to: infoFromOutTxt size) withBlanksTrimmed.
        oc := OrderedCollection new.
        tmp := ''.
        numbers
                do: [:e | e = $
                                ifTrue: [oc add: tmp.
                                        tmp := '']
                                ifFalse: [tmp := tmp asString , e asString]].
        oc
                removeAllSuchThat: [:e | e = ''].

        ^ oc fourth asNumber

E.g.:
Running from workspace:
WindowsOS getInfo: 'explorer'

shows how much RAM is explorer.exe using

Best regards,
Valdas Bucinskas


-----Original Message-----
From: [hidden email]
[mailto:[hidden email]]On Behalf Of David T.
Lewis
Sent: Tuesday, January 31, 2006 2:54 PM
To: The general-purpose Squeak developers list
Subject: Re: Windows process info from Squeak


On Tue, Jan 31, 2006 at 02:34:25PM +0200, Valdas Bucinskas wrote:
> Hello
>
> Is there a way to get information about Windows XP processes from Squeak?
> Smth like how much RAM is the process using? What is PID of the process?
And
> so on.
> Any hints or workaraunds are very much welcome.

See OSProcess and OSProcessPlugin on Squeak Map.

There is an old version of the plugin (Win32OSProcessPlugin.dll)
included in the OSProcess distribution, but you'll need to build
your own from source with VMMaker if you want the latest. The old
one will give you pid, and the more recent OSPP also gives the
environment, the current working directory, main thread ID, etc.
For the other things you might be interested in (memory use),
you might want to just use one of the existing OSPP primitives
as a template and put in whatever you want.

One word of warning, the latest SVN sources for Windows VM have
a security related "feature" that will break some of the OSPP
file-related functions. Let me know if this is a problem for
you and I'll try to come up with some sort of workaround. It's
not something I'm working on at the moment though.

Dave



Reply | Threaded
Open this post in threaded view
|

RE: Windows process info from Squeak

Valdas Bucinskas
In reply to this post by Boris.Gaertner
Hello,
I liked your example a lot. I was playing with it recently, and got some
questions.
1. Is there any documentation on what methods can be called from user32.dll,
kernel32.dll, psapi.dll (the dlls I see in Win32Window instance methods)?
2. I tried to know some information about other process than Squeak.exe, but
couldn't figure out how to do that ?
Comments are as always welcome.

Best regards,
Valdas Bucinskas

-----Original Message-----
From: [hidden email]
[mailto:[hidden email]]On Behalf Of Boris
Gaertner
Sent: Tuesday, January 31, 2006 8:27 PM
To: The general-purpose Squeak developers list
Subject: Re: Windows process info from Squeak


"Valdas Bucinskas" <[hidden email]> wrote:


> Hello
>
> Is there a way to get information about Windows XP processes from Squeak?
> Smth like how much RAM is the process using? What is PID of the process?
> And so on.
> Any hints or workaraunds are very much welcome.

The FFI interface is the framework that you can use to
program what you need.
(see also: http://minnow.cc.gatech.edu/squeak/1414
and http://minnow.cc.gatech.edu/squeak/2422)

To get the process id you have to do this:

1. In Win32Window, add this instance method:

apiGetCurrentProcessId
    <apicall: long 'GetCurrentProcessId' (void) module: 'kernel32.dll'>
    ^self externalCallFailed


2. Then try in a workspace:

Win32Window new apiGetCurrentProcessId

Getting a handle to the current process is not much more
difficult:

1. you have to add these instance methods:


apiGetCurrentProcess
    <apicall: Win32Handle 'GetCurrentProcess' (void) module: 'kernel32.dll'>
    ^self externalCallFailed

apiGetGuiResources: h type: int
    <apicall: long 'GetGuiResources' (Win32Handle long) module:
'user32.dll'>
    ^self externalCallFailed


2. Then you can try:

  | interface |  " gdi resources "
  interface := Win32Window new.
  interface apiGetGuiResources: interface apiGetCurrentProcess type: 0.

 | interface |  " user resources "
  interface := Win32Window new.
  interface apiGetGuiResources: interface apiGetCurrentProcess type: 1.


The attached change set contains these methods and a
class definition that is needed to obtain memory usage information.

Please have a look at the class comment for
Win32ProcessMemoryCounters to find out how you can
obtain memory information.

It is perhaps necessary to explicitely release (with free)
some of the Win32 structures, but I am not sure about
that. Comments are highly welcome.

Hope that helps a bit.
Boris










Reply | Threaded
Open this post in threaded view
|

Re: Windows process info from Squeak

Boris.Gaertner

From: "Valdas Bucinskas" <[hidden email]>

> Hello,
> I liked your example a lot. I was playing with it recently, and got some
> questions.
> 1. Is there any documentation on what methods can be called from
user32.dll,
> kernel32.dll, psapi.dll (the dlls I see in Win32Window instance methods)?
Documentation is a problem. You really need the documentation of
(one of the newer)  Windows SDK.
Programmers that have connection time for free or at a very low rate
can read this documentation in the internet. Programmers that have
access to the IBM Smalltalk system can look into class OSCall and
pool dictionary PlatformFunctions to see what is available for
Windows 95 (To the best of my knowledge, the calls for many
newer API functions are not provided in OSCall, but can easily
be added by an user that needs them.)


> 2. I tried to know some information about other process than Squeak.exe,
but
> couldn't figure out how to do that ?
Newer Windows versions have the API function EnumProcesses
(in psapi.dll) that let you da that. The function writes the IDs of all
processes into an array. In squeak, you use a ByteArray as
argument for the method call and some auxiliary protocol form
ByteArray to convert the bytes into integers.
Once you have the process IDs, you can collect all process-related
information for the processes.

For autentic information, please read this page:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/bas
e/enumprocesses.asp

The attached changes set contains additional methods
for these API functions:
  EnumProcesses
  OpenProcess
  CloseHandle
  LastError

With these you can evaluate this example (you find it also in the
preambble of the change set. ):

  | interface array uint cb x err  handleArray i j  upperIdx oc
processHandle |
  interface := Win32Window new.
  array := ByteArray new: 8000. " sufficient for up to 2000 processes "
  uint := ByteArray new: 4.
  cb := 8000.
  x := interface apiEnumProcesses: array size: cb bytesReturned: uint .
  x ifFalse: [
      err := interface getLastError. err].
  handleArray := OrderedCollection new: 2000.

   " convert the bytes into unsigned integers "
  upperIdx := uint unsignedLongAt: 1.
  j := i := 1.

  [j < upperIdx]
    whileTrue: [
      handleArray add: (array unsignedLongAt: j).

      i := i + 1.
      j := j + 4.

  ].

  "  use the process IDs to open the processes and to query the amount of
resources they use. "
  oc := OrderedCollection new.
 handleArray do: [:idx |
  processHandle := interface getProcessHandleWithAccessRights: 16r400
inherit: true processId: idx.
      processHandle notNil
           ifTrue:
             [ oc add:
              (Array with: idx
                     with: (interface apiGetGuiResources: processHandle
type: 0)
                     with: (interface apiGetGuiResources: processHandle
type: 1)
               ).

      interface closeHandle: processHandle.]
 ].
 oc inspect
  "  It is a nice idea to compare this with the data that are shown in the
     Task Manager "


======================================


I also fixed a bug from the example that I posted yesterday:

The typeSIZE_T is an unsigned long integer (That is what I found in
the file _stddef.h of the Borland c++ compiler). In my example from
yesterday I interpreted these values as signed integers. This is
wrong and should be changed.
The  subclasses of ExternalStructure understand the class method
defineFields that creates the accessors for all items that
are declared in the  fields  method.

You see that the use of FFI is not really difficult; what you have to
do it to translate the specifications from the Microsoft Documentation
into api  calls.

Have success.

Gretings
Boris



FFIWin.2.cs (8K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

RE: [FFI newbie] Windows process info from Squeak

Valdas Bucinskas
Hello,

Wow, your examples are really interesting and helps incredibly much.
I modified your your last example slightly, incorporating RAMs used by the
process. And then tried to find the .exe that calls the process. It appears,
the method GetModuleBaseName from psapi.dll should be used, which is
described in
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/bas
e/getmodulebasename.asp.
It gives the method declaration is
DWORD GetModuleBaseName(
  HANDLE hProcess,
  HMODULE hModule,
  LPTSTR lpBaseName,
  DWORD nSize
);
What I miss now is the knowledge, how do I convert types from c++ like into
Sueak ones. I guess hProcess corresponds to Win32Handle, lpBaseName
corresponds  to char*, and nSize corresponds to long. GetModuleBaseName
returns long.
1. But what does hModule correspond to?
My guess
        <apicall: long 'GetModuleBaseName' (Win32Handle Win32Handle char* long)
module: 'psapi.dll'>
throughs Error 13, which is 'The data is invalid.'
2. Should a class similar to Win32Handle be created in order to hModule
typecasting work?

================

Modified piece of code (stopped while trying to make the apiGetProcessName
work ):

        "use the process IDs to open the processes and to query the amount of
        resources they use."
        oc := OrderedCollection new.
        handleArray
                do: [:idx |
                        processHandle := interface
                                                getProcessHandleWithAccessRights: 1024
                                                inherit: true
                                                processId: idx.
                        processHandle notNil
                                ifTrue: [memRec := Win32ProcessMemoryCounters new.
                                        interface
                                                apiGetProcessMemoryInfoFor: processHandle
                                                into: memRec
                                                descriptorSize: memRec class byteSize.
                                        processName := ''.
                                        processInfo := Dictionary new.
                                        processInfo at: 'PID' put: idx.
                                        processInfo
                                                at: 'GDI Objects'
                                                put: (interface apiGetGuiResources: processHandle type: 0).
                                        processInfo
                                                at: 'USER Objects'
                                                put: (interface apiGetGuiResources: processHandle type: 1).
                                        processInfo at: 'Mem Usage' put: memRec WorkingSetSize.
                                        processInfo at: 'Process Name' put: nil.
"(interface apiGetProcessName: processHandle module: nil  into: processName
size: 40)."
                                        oc add: processInfo.
                                        interface closeHandle: processHandle]].
        ^ oc
"It is a nice idea to compare this with the data that are shown in the
        Task Manager
Yeah, it is the same! It is like a little Task Manager in Squeak!
"

Best regards,
Valdas Bucinskas


Reply | Threaded
Open this post in threaded view
|

Re: [FFI newbie] Windows process info from Squeak

Bert Freudenberg-3

Am 02.02.2006 um 12:30 schrieb Valdas Bucinskas:

> Hello,
>
> Wow, your examples are really interesting and helps incredibly much.
> I modified your your last example slightly, incorporating RAMs used  
> by the
> process. And then tried to find the .exe that calls the process. It  
> appears,
> the method GetModuleBaseName from psapi.dll should be used, which is
> described in
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ 
> perfmon/bas
> e/getmodulebasename.asp.
> It gives the method declaration is
> DWORD GetModuleBaseName(
>   HANDLE hProcess,
>   HMODULE hModule,
>   LPTSTR lpBaseName,
>   DWORD nSize
> );
> What I miss now is the knowledge, how do I convert types from c++  
> like into
> Sueak ones. I guess hProcess corresponds to Win32Handle, lpBaseName
> corresponds  to char*, and nSize corresponds to long.  
> GetModuleBaseName
> returns long.
> 1. But what does hModule correspond to?
> My guess
> <apicall: long 'GetModuleBaseName' (Win32Handle Win32Handle char*  
> long)
> module: 'psapi.dll'>
> throughs Error 13, which is 'The data is invalid.'

You have to check what HMODULE actually is. Look in the  
documentation, the header files, or some cpp output.

Or guess ;-)

> 2. Should a class similar to Win32Handle be created in order to  
> hModule
> typecasting work?

My guess would be hModule is just a handle as well (it starts with an  
h, and Windows API uses Simonyi's ["the Hungarian"] notation), so try  
Win32Handle as type. Or just "long", because Windows handles are ints  
in the end, right? We only deal with bits here, no compiler clue  
cudgel needed.

- Bert -


Reply | Threaded
Open this post in threaded view
|

RE: [FFI newbie] Windows process info from Squeak

Boris.Gaertner
In reply to this post by Valdas Bucinskas

"Valdas Bucinskas" <[hidden email]> wrote:


> Hello,
>
> Wow, your examples are really interesting and helps incredibly much.
> I modified your your last example slightly, incorporating RAMs used by the
> process. And then tried to find the .exe that calls the process. It
> appears,
> the method GetModuleBaseName from psapi.dll should be used, which is
> described in
>
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/bas

> e/getmodulebasename.asp.
> It gives the method declaration is
> DWORD GetModuleBaseName(
>   HANDLE hProcess,
>   HMODULE hModule,
>   LPTSTR lpBaseName,
>   DWORD nSize
> );
> What I miss now is the knowledge, how do I convert types from c++ like
> into
> Sueak ones. I guess hProcess corresponds to Win32Handle, lpBaseName
> corresponds  to char*, and nSize corresponds to long. GetModuleBaseName
> returns long.
> 1. But what does hModule correspond to?
> My guess
> <apicall: long 'GetModuleBaseName' (Win32Handle Win32Handle char* long)
> module: 'psapi.dll'>

almost correct, but the name of the function is
    'GetModuleBaseNameA'
where the last character stands for ASCII.
A DLL contents viewer helps a lot to find out such details,
I use this one: http://www.nirsoft.net/utils/dll_export_viewer.html


> throughs Error 13, which is 'The data is invalid.'
> 2. Should a class similar to Win32Handle be created in order to hModule
> typecasting work?
No, that is not needed,  hModule is a handle, Win32Handle is the right
choice.


No please try this:

1. add this api method to Win32Window:

apiGetModuleBaseName: hProcess module: hModule into: lpString bufferSize:
size
   <apicall: long 'GetModuleBaseNameA' (Win32Handle Win32Handle char* long)
module: 'psapi.dll'>
   ^self externalCallFailed

2. Ensure that you open the process handle with access rights 16r410 (this
is
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, the access
right alone PROCESS_QUERY_INFORMATION does not allow you tho read the name)
(The processes System, Idle and some others will not tell you their
names anyway)

3. Do something like this:

 handleArray do: [:idx |
     processHandle := interface getProcessHandleWithAccessRights: 16r410
                             inherit: true processId: idx.
     processHandle notNil
       ifTrue:
         [  | buffer processName cnt |
          buffer := ByteArray new: 80.
          interface apiGetModuleBaseName: processHandle
                    module: nil into: buffer bufferSize: 80.
          processName := WriteStream on: (String new: 80).
          cnt := 1.
          [i <= 80 and: [(buffer at: cnt) ~= 0]]
             whileTrue:
               [processName nextPut: (Character value: (buffer at: cnt)).
                            cnt := cnt + 1].
          processName := processName contents.
          oc add:
           (Array with: idx
                     with: (interface apiGetGuiResources: processHandle
                                      type: 0)
                     with: (interface apiGetGuiResources: processHandle
                                      type: 1)
                     with: processName).
             
            interface closeHandle: processHandle.
         ]  
 ].

When you have to provide buffers that are filled with some information,
it is always a good choice to use ByteArrays of suitable size. You
can always convert a ByteArray into a number or into a string.


Hope this helps,
Boris

Reply | Threaded
Open this post in threaded view
|

RE: [FFI newbie] Windows process info from Squeak

Valdas Bucinskas
Hello Boris,

Thanks man! You helped me greatly, saving some weaks (months) of tedious
work. Your examples were the enormous help. You could be a tallented teacher
:)

Best regards,
Valdas Bucinskas


-----Original Message-----
From: [hidden email]
[mailto:[hidden email]]On Behalf Of "Boris
Gartner"
Sent: Thursday, February 02, 2006 5:12 PM
To: The general-purpose Squeak developers list
Subject: RE: [FFI newbie] Windows process info from Squeak


No please try this:

1. add this api method to Win32Window:

apiGetModuleBaseName: hProcess module: hModule into: lpString bufferSize:
size
   <apicall: long 'GetModuleBaseNameA' (Win32Handle Win32Handle char* long)
module: 'psapi.dll'>
   ^self externalCallFailed

2. Ensure that you open the process handle with access rights 16r410 (this
is
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, the access
right alone PROCESS_QUERY_INFORMATION does not allow you tho read the name)
(The processes System, Idle and some others will not tell you their
names anyway)

3. Do something like this:

 handleArray do: [:idx |
     processHandle := interface getProcessHandleWithAccessRights: 16r410
                             inherit: true processId: idx.
     processHandle notNil
       ifTrue:
         [  | buffer processName cnt |
          buffer := ByteArray new: 80.
          interface apiGetModuleBaseName: processHandle
                    module: nil into: buffer bufferSize: 80.
          processName := WriteStream on: (String new: 80).
          cnt := 1.
          [i <= 80 and: [(buffer at: cnt) ~= 0]]
             whileTrue:
               [processName nextPut: (Character value: (buffer at: cnt)).
                            cnt := cnt + 1].
          processName := processName contents.
          oc add:
           (Array with: idx
                     with: (interface apiGetGuiResources: processHandle
                                      type: 0)
                     with: (interface apiGetGuiResources: processHandle
                                      type: 1)
                     with: processName).

            interface closeHandle: processHandle.
         ]
 ].

When you have to provide buffers that are filled with some information,
it is always a good choice to use ByteArrays of suitable size. You
can always convert a ByteArray into a number or into a string.


Hope this helps,
Boris