The win32 kernel supports a range of some important object types. E.g. we
have Processes, Threads or Events and Mutexes. All
those objects are supported by APIs, which are exported from kernel32.dll.
First let's look at the full list of available kernel objects. Please note
that some objects are only available in either the win9x or winNT family:
 |
type
TKernelObjType = (otUnknown,
otSemaphore,
otEvent,
otMutex,
otProcess,
otThread,
otTimer,
otFileMapping,
otFile,
otSnapshot,
otNotification,
otComPort,
otPipe,
otMailslot,
otSocket,
otVxd,
otConsoleInput,
otConsoleOutput,
otDirectory,
otSymbolicLink,
otToken,
otWindowStation,
otDesktop,
otKey,
otPort,
otIoCompletion,
otKeyedEvent);
|
|
madKernel implements one base interface for all the listed kernel objects,
which is named "IKernelObj". See also the IKernelObj Reference.
 |
type IKernelObj = interface (IBasic) ['{72518460-8D63-11D3-A52E-00005A180D69}'];
|
|
The following methods are supported for all kernel objects:
 |
property IKernelObj. ObjType : TKernelObjType;
property IKernelObj. ObjTypeStr : string;
property IKernelObj. ObjAddr : pointer;
CurrentProcess.ObjType -> otProcess
CurrentThread .ObjTypeStr -> 'Thread'
|
|
In the winNT family we can find out the name of the object. What the name is
depends on that type of the object. E.g. for files this is the full file
path. Unfortunately this method doesn't work for the win9x family.
 |
property IKernelObj. ObjName : string;
Handle(CreateMutex(nil, false, 'TestMutex')).KernelObj.ObjName -> '\BaseNamedObjects\TestMutex'
|
|
If we have a thread or
process kernel object, we can also ask the ID of
the object. Only threads and processes have an ID, all other
objects don't:
If we have an event kernel object, we can
ask whether we have an auto event or a manual event. Obviously this method
only works for event kernel objects:
 |
function IKernelObj. IsAutoEvent : boolean;
NewEvent(false).IsAutoEvent -> false
Handle(CreateEvent(nil, false, true, nil)).KernelObj.IsAutoEvent -> true
|
|
Most win32 APIs only accept kernel object handles, so with this
property you can get a handle to our kernel object. If no handle is
available yet, a new one is created, e.g. by using OpenProcess for a
process kernel object. The new handle will be
opened with full access rights, if possible.
If you want, you can list all handles which the current process has
open for this specific kernel object:
 |
property IKernelObj. Handles : IHandles;
|
|
Some kernel objects can be waited for, e.g. Events and Mutexes, but
also Processes and Threads. So we have a second base interface,
which implements general waiting functionality for those kind of kernel
objects. This interface is called "IWaitableObj". See the
IWaitableObj Reference. Additionally we have another base interface,
which can hold a list of waitable objects. It's called "IWaitableObjs". See
also the IWaitableObjs Reference.
 |
type
IWaitableObj = interface (IKernelObj) ['{72518461-8D63-11D3-A52E-00005A180D69}'];
IWaitableObjs = interface (ICustomBasicList) ['{A1DB3222-8EB8-11D3-A52E-00005A180D69}'];
|
|
Now let's first define some types and constants which are needed for the
following "WaitFor" methods/functions:
 |
type
TWaitForMessage = (wfKey, wfMouseMove, wfMouseButton, wfPostMessage,
wfTimer, wfPaint, wfSendMessage, wfHotKey, wfAllPostMessage);
TWaitForMessages = set of TWaitForMessage;
const
CWaitForAllEvents : TWaitForMessages = [wfKey, wfMouseMove, wfMouseButton,
wfPostMessage, wfTimer, wfPaint,
wfHotKey];
CWaitForAllInput : TWaitForMessages = [wfKey, wfMouseMove, wfMouseButton,
wfPostMessage, wfTimer, wfPaint,
wfSendMessage, wfHotKey];
CWaitForInput : TWaitForMessages = [wfKey, wfMouseMove, wfMouseButton];
CWaitForMouse : TWaitForMessages = [ wfMouseMove, wfMouseButton];
|
|
There are several "WaitFor" methods/functions. You can wait for one
"IWaitableObj" kernel object or for multiple "IWaitableObjs" kernel objects.
"WaitFor" waits, until the specified objects enter "signaled state". E.g. a
process is in signaled state, if it is not running anymore. If you set
"waitAll = false", the wait is stopped as soon as one of the specified
objects is signaled. In that case the index of the signaled object is
returned.
 |
function IWaitableObj. WaitFor (milliseconds : cardinal = INFINITE;
handleMessages : boolean = true ) : boolean;
function IWaitableObjs. WaitFor (waitAll : boolean = false;
milliseconds : cardinal = INFINITE;
handleMessages : boolean = true;
index : TPInteger = nil ) : boolean;
function WaitFor (const objects : array of IBasic;
waitAll : boolean = false;
milliseconds : cardinal = INFINITE;
handleMessages : boolean = true;
msgs : TWaitForMessages = [];
alertable : boolean = false ) : integer; overload;
function WaitFor (const objects : ICustomBasicList;
waitAll : boolean = false;
milliseconds : cardinal = INFINITE;
handleMessages : boolean = true;
msgs : TWaitForMessages = [];
alertable : boolean = false ) : integer; overload;
NewProcess('calc.exe').WaitFor;
WaitFor([Process('calc.exe'), Process('notepad.exe')], true);
|
|
The "Notify" methods/functions don't wait, they return at once. But the
specified 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 IWaitableObj. Notify (window : cardinal;
msg : cardinal ) : boolean;
function IWaitableObjs. Notify (window : cardinal;
msg : cardinal;
waitAll : boolean = false) : boolean;
function Notify (window : cardinal;
msg : cardinal;
const objects : array of IBasic;
waitAll : boolean;
msgs : TWaitForMessages;
alertable : boolean ) : boolean; overload;
function Notify (window : cardinal;
msg : cardinal;
const objects : ICustomBasicList;
waitAll : boolean = false;
msgs : TWaitForMessages = [];
alertable : boolean = false) : boolean; overload;
procedure ExplorerWasClosed(window, msg: cardinal; wParam, lParam: integer; var result: integer);
begin
MessageBox(0, 'Explorer was closed!', 'info', 0);
end;
initialization
Process('explorer.exe').Notify(MsgHandlerWindow, AddMsgHandler(ExplorerWasClosed));
end.
|
|
The "WouldWait" methods/functions test, whether we would have to wait for
the specified objects:
 |
function IWaitableObj. WouldWait : boolean;
function IWaitableObjs. WouldWait (waitAll: boolean) : boolean;
function WouldWait (const objects : array of IBasic;
waitAll : boolean = false ) : boolean; overload;
function WouldWait (const objects : ICustomBasicList;
waitAll : boolean = false ) : boolean; overload;
boolVar := Mutex(aMutexHandle).WouldWait;
|
|
Finally we have an interface for all the kernel objects that have no own
interface (yet).
 |
type IOtherKernelObj = interface (IKernelObj) ['{4910FAC0-B61E-11D3-A530-00005A180D69}'];
|
|