Handles 

www.madshi.net

In Windows we have different kind of handles. There are kernel object handles, GDI handles and Window handles, to name the most important types of handles. The "handle" functionality in madKernel is about kernel object handles. In short we're talking about those handles which can be closed with the kernel32 API "CloseHandle".

What exactly is a kernel object handle? Internally it consists of two elements, namely an access mask and a pointer to a kernel object. That's it. A kernel handle gives you access to a specific kernel object with specific access rights. Now madKernel encapsulates a lot of handle functionality in an interface with the name (you won't believe it) "IHandle". See also the IHandle Reference. Furthermore there is also an interface for a list of handles. See the IHandles Reference.

type
  IHandle  = interface (IBasic)           ['{86522220-8323-11D3-A52D-00005A180D69}'];
  IHandles = interface (ICustomBasicList) ['{B3017220-8338-11D3-A52D-00005A180D69}'];

There are several ways to get a valid IHandle instance. You can use the property IKernelObj.Handle to get a handle to a specific kernel object, or you can use IProcess.Handles to get a list of handles that a specific process has open. Or you can use one of the following two functions. The function "Handle" accepts a typical win32 handle dword value. If you set "autoClose" to "true", the handle is kind of eaten by the interface. That means, if the interface is freed, the win32 handle is automatically closed. The function "Handles" enumerates all handles which are opened by the current process or by all processes system wide.

function Handle (handle    : cardinal;
                 autoClose : boolean = true) : IHandle; overload;

function Handles (systemWide: boolean = false) : IHandles;

// Examples:
Handle(CreateMutex(nil, false, nil)).KernelObj.ObjTypeStr  ->  'Mutant'
MessageBox(0, pchar('We have ' + IntToStr(Handles.ItemCount) + ' open kernel handles.'), 'info', 0);

Now let's look at the basic properties of the "IHandle" interface. We can ask the win32 handle value, the access mask of this handle and the type of the referenced kernel object. Finally we can also get an interface instance of the kernel object which is represented by this handle:

property IHandle.Handle    : cardinal;        // win32 handle dword value
property IHandle.Access    : cardinal;        // object type specific access mask
property IHandle.ObjType   : TKernelObjType;
property IHandle.KernelObj : IKernelObj;

// Example:
var hnd : IHandle;
begin
  hnd := Handle(CreateMutex(nil, false, nil));
  MessageBox(0, pchar('New mutex access: ' + IntToHex(hnd.Access, 1)), 'info', 0);
end;

If you set the "AutoClose" property to "true", the win32 handle dword value (which is encapsulated by the IHandle instance) gets closed as soon as the IHandle instance gets freed. If the "AutoClose" property is set to "false", the win32 handle survives the IHandle instance. In this case you eventually have to close the win32 handle manually by calling "CloseHandle".

property IHandle.AutoClose : boolean;

Sometimes it might be possible, that the win32 handle is closed behind our back. So with the property "IsStillValid" we can check, whether our IHandle instance still makes sense.

function IHandle.IsStillValid : boolean;

Sometimes you need to duplicate a handle. With the methods "Duplicate" you can easily do so. You can duplicate a handle into your own process or in any target process (if you have enough privileges). "targetProcess = 0" stands for the current process.

function IHandle.Duplicate (autoClose           : boolean;
                            access              : cardinal;
                            inheritHandles      : boolean;
                            const targetProcess : IProcess       ) : IHandle; overload;
function IHandle.Duplicate (autoClose           : boolean;
                            access              : cardinal;
                            inheritHandles      : boolean;
                            const targetProcess : IHandle        ) : IHandle; overload;
function IHandle.Duplicate (autoClose           : boolean  = true;
                            access              : cardinal = 0;
                            inheritHandles      : boolean  = true;
                            targetProcess       : cardinal = 0   ) : IHandle; overload;

You can wait for one or for multiple handles. If you set "waitAll" to "false", the wait is over, if one handle (or rather the object represented by the handle) is signaled. In that case the index of the signaled handle (object) is returned.

function IHandle. WaitFor (milliseconds   : cardinal  = INFINITE;
                           handleMessages : boolean   = true    ) : boolean;
function IHandles.WaitFor (waitAll        : boolean   = false;
                           milliseconds   : cardinal  = INFINITE;
                           handleMessages : boolean   = true;
                           index          : TPInteger = nil     ) : boolean;

The "Notify" methods don't wait, they return at once. But the specified handles (respectively the represented kernel objects) are watched for in the background. As soon as the wanted state is reached, a notification message is sent to the specified window:

function IHandle. Notify (window  : cardinal;
                          msg     : cardinal       ) : boolean;
function IHandles.Notify (window  : cardinal;
                          msg     : cardinal;
                          waitAll : boolean = false) : boolean;

The "WouldWait" methods test, whether we would have to wait for the specified handles (kernel objects):

function IHandle. WouldWait : boolean;
function IHandles.WouldWait (waitAll: boolean) : boolean;

Of course the IHandles interfaces has properties/methods to get easy access to the items. Also you can easily refresh the handle list, that is you can look for new, deleted or changed handles.

property IHandles.Items [index: integer] : IHandle;

function IHandles.RefreshItems : boolean;

If this IHandle(s) instance resulted from an enumeration, we can ask the enumeration parameters.

property IHandle. OwnerProcess : IProcess;
property IHandles.OwnerProcess : IProcess;
property IHandles.KernelObj    : IKernelObj;