Processes 

www.madshi.net

Probably the most important kernel object is the "Process". madKernel implements two interfaces for this object type. "IProcess" encapsulates a single process object, while "IProcesses" makes handling with a list of processes comfortable. See also the IProcess Reference and the IProcesses Reference.

type
  IProcess   = interface (IWaitableObj ) ['{D2097382-9AB1-11D3-A530-00005A180D69}'];
  IProcesses = interface (IWaitableObjs) ['{D2097381-9AB1-11D3-A530-00005A180D69}'];

As with most other madKernel interfaces there are several ways to get an IProcess or an IProcesses instance. You can use IThread.OwnerProcess or IWindow.OwnerProcess or one of the following functions. You can either directly create a "NewProcess" or print a file with "PrintFile", which also results in a new process being created. Or you can get the "CurrentProcess" or the current process' "ParentProcess" (the one that created the current process). Also you can convert a win32 handle dword value or an IHandle instance into an IProcess instance. Or you can get a process by executable file name/path. Finally you can call "Processes" to get a list of the processes which are currently running or to get a list of instances of a specific executable file name/path.

function NewProcess (exeFile        : string;
                     params         : string              = '';
                     workingDir     : string              = '';
                     showCmd        : cardinal            = SW_SHOWDEFAULT;
                     creationFlags  : cardinal            = 0;
                     processAttr    : PSecurityAttributes = nil;
                     threadAttr     : PSecurityAttributes = nil;
                     inheritHandles : boolean             = true;
                     environment    : pointer             = nil           ) : IProcess;

function PrintFile (file_      : string;
                    workingDir : string   = '';
                    showCmd    : cardinal = SW_SHOWNORMAL) : IProcess;

function CurrentProcess : IProcess;
function ParentProcess  : IProcess;

function Process (const process : IHandle       ) : IProcess; overload;
function Process (process       : cardinal;
                  autoClose     : boolean = true) : IProcess; overload;
function Process (exeFile       : string        ) : IProcess; overload;

function Processes (exeFile: string = '*') : IProcesses; overload;

// Examples:
NewProcess('calc.exe').WaitFor;
PrintFile('c:\test.bmp').WaitFor;
Assert(CurrentProcess.ParentProcess = ParentProcess);
Processes('notepad.exe').Terminate;
if Process('explorer.exe').IsValid then ...

You can check whether the process object represented by this IProcess instance is still valid. Also you can check whether the process is still running or whether it was already closed.

function IProcess.IsStillValid   : boolean;
function IProcess.IsStillRunning : boolean;

// Example:
Assert(CurrentProcess.IsStillRunning);

In TerminalServer environments there are multiple sessions. Each process running on a TerminalServer belongs to one of those sessions. XP fast user switching internally is based on TerminalServer, too, so there each fast user session also has its own session identifier.

property IProcess.Session : cardinal;

// Example:
CurrentProcess.Session  ->  0  // the default session ID is 0

Asks the exe file name (including path) of this process:

property IProcess.ExeFile : string;

// Example:
Process('explorer.exe').ExeFile  ->  'C:\Windows\Explorer.exe'

To get a handle with full access rights, you can simply use the property IKernelObj.Handle. If you need specific access rights, you can call the method "GetHandle" and enter the access rights you need. Please note, that madKernel takes your access wish as the minimum. That means it is possible (due to handle caching) that you get a handle back, which has all the access rights you need plus some more rights you didn't ask for.

function IProcess.GetHandle (access: cardinal = PROCESS_ALL_ACCESS) : IHandle;

In win9x you can call "StoreHandle" to tell madKernel that the handles for this thread should be cached. You can call "StoreHandle" as often as you like, but please call "ReleaseHandle" once for each "StoreHandle" call. In winNT handles are always cached, so there these properties are ignored.

procedure IProcess.StoreHandle;    // win9x only
procedure IProcess.ReleaseHandle;  // win9x only

Who is the creator of this process?

property IProcess.ParentProcess : IProcess;

// Example:
if PosText('delphi32.exe', CurrentProcess.ParentProcess.ExeFile) > 0 then
  MessageBox(0, 'running inside of Delphi IDE', 'info', 0);

Use the following methods to get the version and type of the OS for which this process was built:

type
  TOsVersion = packed record
    minor : word;
    major : word;
  end;
  TExeType = (etUnknown, etDos, etWin16, etConsole, etWin32);

property IProcess.OsVersion : TOsVersion;
property IProcess.ExeType   : TExeType;

// Example:
Assert(CurrentProcess.ExeType in [etConsole, etWin32]);

Which icon is shown for this process in the explorer?

function IProcess.Icon (smallIcon             : boolean = true;
                        linkOverlayIfLnkOrPif : boolean = false) : cardinal;

The following two methods return the main module (= executable module) of this process. "HInstance" returns the module handle (= pointer to the executable image in memory), while "MainModule" returns an IModule instance.

property IProcess.HInstance  : cardinal;
property IProcess.MainModule : IModule;

// Examples:
Assert(CurrentProcess.HInstance = HInstance);
Assert(CurrentProcess.ExeFile = CurrentProcess.MainModule.FileName);

Use the property "ServiceProcess" to access (read/write) the service flag of this process. A service process is not being listed in the task manager and also survives logoff (if WM_ENDSESSION is handled correctly, what Delphi doesn't do). This property is only available in win9x.

property IProcess.ServiceProcess : boolean;  // win9x only

// Examples:
CurrentProcess.ServiceProcess := true;  // hide me

The following properties give you access to the priority parameters of this process. Please see the documentation of the win32 APIs "GetPriorityClass" and "GetProcessPriorityBoost" for more information.

type TPriorityClass = (pcUnknown, pcIdle, pcNormal, pcHigh, pcRealTime);

property IProcess.PriorityClass : TPriorityClass;
property IProcess.PriorityBoost : boolean;

// Example:
CurrentProcess.PriorityClass := pcRealTime;  // not recommended!

Access to this process' affinity mask (see "GetProcessAffinityMask" API).

property IProcess.AffinityMask : cardinal;

Use the following methods to get and set the working set size of this process (see "GetProcessWorkingSetSize" API).

procedure IProcess.GetWorkingSetSize (var minimum, maximum: cardinal);
function  IProcess.SetWorkingSetSize (    minimum, maximum: cardinal) : boolean;

Get the command line string and the TStartupInfo record with which this process was created. This works on other processes, as well.

property IProcess.CommandLine : string;
property IProcess.StartupInfo : TStartupInfo;

// Example:
Process('explorer.exe').CommandLine  ->  'C:\Windows\Explorer.exe'

The following methods allow you to allocate and access memory of this process. In winNT the parameter "mayUseSharedArea" has no meaning. In win9x it specifies whether it's okay to use shared memory for the allocation or whether it must be a real private memory allocation in the destination process. Allocating shared memory in win9x is faster, but shared memory is more precious, so by default shared memory is not used.

function IProcess.AllocMem (size             : integer;
                            mayUseSharedArea : boolean = false) : pointer;
function IProcess.FreeMem  (var ptr          : pointer        ) : boolean;

function IProcess.ReadMemory  (const source; var dest; count: integer) : boolean;
function IProcess.WriteMemory (const source; var dest; count: integer) : boolean;
function IProcess.ZeroMemory  (              var dest; count: integer) : boolean;

This method creates a remote thread in the destination process. This works in both winNT and win9x:

function IProcess.CreateThread (startAddr     : pointer;
                                parameter     : pointer             =   nil;
                                creationFlags : cardinal            =     0;
                                stackSize     : cardinal            =     0;
                                threadAttr    : PSecurityAttributes =   nil) : IThread;

The following methods return an IModule instance to the specified module of this process.

function IProcess.Module (handle    : cardinal;
                          autoClose : boolean = false) : IModule; overload;
function IProcess.Module (memory    : pointer;
                          autoClose : boolean = false) : IModule; overload;
function IProcess.Module (fileName  : string;
                          autoClose : boolean = false) : IModule; overload;

To inject a module (dll) into the destination process you can use the method "LoadModule". If you set "autoClose" to "true", the module is unloaded again as soon as the resulting IModule instance is freed. If you don't want that, please set "autoClose" to "false".

function IProcess.LoadModule (fileName          : string;
                              autoClose         : boolean = true;
                              withoutReferences : boolean = false;
                              onlyAsDataFile    : boolean = false;
                              alteredSearchPath : boolean = false;
                              timeOut           : integer = 3000 ) : IModule;

// Example:
Process('explorer.exe').LoadModule('hookExpl.dll', false);

The following methods return a list of what belongs to this process. Most of the methods are easy to understand. The "ExportList" contains all exported functions of all modules loaded in this process. The "TaskbarWindows" are those windows, which belong to this process and are shown in the task bar.

property IProcess.Modules        : IModules;
property IProcess.ExportList     : IXxportList;
property IProcess.TrayIcons      : ITrayIcons;
property IProcess.Windows_       : IWindows;
property IProcess.TaskbarWindows : IWindows;
property IProcess.Threads        : IThreads;
property IProcess.Handles        : IHandles;

// Examples:
MessageBox(0, pchar(IntToStr(CurrentProcess.Windows_.ItemCount) + ' windows belong to me!'), 'info', 0);
Process('msimn.exe').TrayIcons.Delete;  // delete outlook's tray icons

In order to minimize, maximize or restore this process you can call one of the following methods:

function IProcess.Minimize (activate: boolean = false) : boolean;
function IProcess.Maximize (activate: boolean = true ) : boolean;
function IProcess.Restore  (activate: boolean = true ) : boolean;

// Example:
Process('notepad.exe').Minimize;

If you want to execute a specific function inside of the context of this destination process, you can do so by calling "ExecuteFunction". As a result the specified function "func" is copied from our process to the other process and executed there. All parameters must be valid in OUR process. They're automatically mapped into the context of the other process. Please note, that the specified function must not call any other functions, only APIs which are exported by system dlls may be called.

type TExecuteFunctionProc = procedure (var params);

function IProcess.ExecuteFunction (func                 : TExecuteFunctionProc;
                                   timeOut              : cardinal = 1000;
                                   params               : pointer  = nil;
                                   paramsSize           : cardinal = 0;
                                   acceptUnknownTargets : boolean  = false) : boolean;

// Example:
procedure ShowMessageBox(var params);
var arrCh : array [0..MAX_PATH] of char;
begin
  GetModuleFileName(0, arrCh, MAX_PATH);
  MessageBox(0, arrCh, pchar(@params), 0);
end;

Process('notepad.exe').ExecuteFunction(ShowMessageBox, INFINITE, pchar('yep!'), 5);

If you want to suspend or resume this process simply call:

function IProcess.Suspend : boolean;
function IProcess.Resume  : boolean;

// Example:
CurrentProcess.Suspend;  // freeze me

The following method waits until this process is ready for receiving user input:

function IProcess.WaitForInputIdle (timeOut: cardinal = INFINITE) : boolean;

You can close this process by either calling "Close" (WM_CLOSE to the main window), "Quit" (WM_QUIT to the main thread), "Exit_" (ExitProcess in the context of the process) or "Terminate" (TerminateProcess). The only recommended way to close another application is to use "Close". But if you don't like that "Do you want to save the changed file?" question, you can use one of the 3 other possibilities. Some processes like being stopped by "Quit", others don't, they prefer "Exit_". Again other processes only react properly on "Terminate". The most hard/forced way of stopping a process is using "Terminate". But this can result in broken data files and such things.

function IProcess.Close     : boolean;
function IProcess.Quit      : boolean;
function IProcess.Exit_     (exitCode: cardinal = 0) : boolean;
function IProcess.Terminate (exitCode: cardinal = 0) : boolean;

// Examples:
Process('calc.exe').Close;
Process('notepad.exe').Quit;

Asks the process's exit code. If the process is still running, you'll get "STILL_ACTIVE".

property IProcess.ExitCode : cardinal;

The following method asks how much time the process has spent with process creation, with process exiting, in kernel land and in user land. This method works only in winNT.

function IProcess.GetTimes (var creation, exit, kernel, user: int64) : boolean;  // only winNT

The following methods can be used to get token information about the process, or the user name the process is running under.

// the resulting string is a data buffer containing the requested record
property IProcess.TokenInformation [tokenLevel: TTokenInformationClass] : AnsiString;

property IProcess.UserName : AnsiString;

Of course the IProcesses interface allows easy access to it's items. Furthermore you can refresh the process list, if you like (that is look for new, deleted and changed processes).

property IProcesses.Items [index: integer] : IProcess;

function IProcesses.RefreshItems : boolean;

The following IProcesses methods are more or less identical to the IProcess methods with the same name. It's just that if you call the IProcesses methods, they are called for all processes in the list.

procedure IProcesses.SetServiceProcess (serviceProcess: boolean = true);

procedure IProcesses.SetPriorityClass (priorityClass: TPriorityClass);
procedure IProcesses.SetPriorityBoost (priorityBoost: boolean       );

procedure IProcesses.SetAffinityMask (affinityMask: cardinal);

function IProcesses.SetWorkingSetSize (minimum, maximum: cardinal) : boolean;

function IProcesses.Minimize (activate: boolean = false) : boolean;
function IProcesses.Maximize (activate: boolean = true ) : boolean;
function IProcesses.Restore  (activate: boolean = true ) : boolean;

function IProcesses.IsStillRunning (all: boolean = false) : boolean;

function IProcesses.Suspend : boolean;
function IProcesses.Resume  : boolean;

function IProcesses.Close     : boolean;
function IProcesses.Quit      : boolean;
function IProcesses.Exit_     (exitCode: cardinal = 0) : boolean;
function IProcesses.Terminate (exitCode: cardinal = 0) : boolean;

// Example:
Processes('calc.exe').Close;
Processes.Minimize;

Does this IProcesses instance only enumerate instances of a specific executable file name/path?

property IProcesses.ExeFile : string;

The following two functions give you the icon and the executable type of the specified executable file:

function Icon (file_                 : string;
               smallIcon             : boolean = true;
               linkOverlayIfLnkOrPif : boolean = false) : cardinal;

function ExeType (exeFile: string) : TExeType;