About Terminal Server, Citrix, Delphi and other stuff
As you know, many kernel32.dll functions, which are working with named objects, like OpenEvent, can be used to work with global and local objects. So what are global and local objects? Global objects are created in session 0 and are actually located in the \BaseNamedObjects directory, while local objects are created in the caller’s session (for example in the \Sessions\5\BaseNamedObjects directory (for session 0, global and local has no meaning since they point to the same object)). MSDN says that you can access only the objects in your own session(via the Local\ prefix) and in session 0 (via the Global\ prefix). But what if you need to access an object in another session? There is nothing in MSDN about it, only this page says “The “Local”, “Global”, and “Session” prefixes are reserved for system use and should not be used as names for kernel objects.” Let’s look at it via WinObj tool:
As you see, we’re now in session 3. \Sessions\3\BaseNamedObjects contains 3 links: Global, which points to \BaseNamedObjects, Local, which just points to itself (\Sessions\3\BaseNamedObjects), and Session, which points to \Sessions\BNOLINKS. Let’s look at the content of the BNOLINKS directory:
Aha, so it seems that this directory just contains the links to the other sessions’ BaseNamedObjects directories (I think, BNOLINKS stands for Base Named Objects Links)! So if you need to access an object in, for example, session 2, you can open it using the Session link: “Session\2\ObjectName“. At first, Session will be resolved to \Sessions\BNOLINKS\2\ObjectName, then \Sessions\BNOLINKS\2 will be resolved to \Sessions\2\BaseNamedObjects\ObjectName, which means, that we’re now accessing object ObjectName of session 2!
Let’s write a simple program, which will create and open objects in other sessions:
At first, we need to get the session list:
TTSEnumArray = packed array[0..65535] of TTSEnum;
PTSEnumArray = ^TTSEnumArray;
function WinStationEnumerateW(
hServer: THandle;
var ppBuffer : PTSEnumArray;
var lpCount : DWORD
) : Boolean; stdcall; external ‘winsta.dll’;
function WinStationFreeMemory(P : Pointer) : Bool; stdcall; external ‘winsta.dll’;
procedure TForm1.FormCreate(Sender: TObject);
var
Sessions : PTSEnumArray;
Count : DWORD;
I : Integer;
begin
if WinStationEnumerateW(0, Sessions, Count) then
try
for I := 0 to Count – 1 do
CreateCheckBox(I, Sessions^[I].SessionId);
finally
WinStationFreeMemory(Sessions)
end
else
for I := 0 to 19 do
CreateCheckBox(I, I);
end;
Then we can create objects in other sessions:
procedure TForm1.ForAllCheckBoxDo(Proc: TOnCheckBoxEvent);
var
I : Integer;
begin
for I := 0 to ScrollBox1.ControlCount – 1 do
if ScrollBox1.Controls[i] is TCheckBox then
Proc(ScrollBox1.Controls[i] as TCheckBox);
end;
procedure TForm1.OnCreateEvent(CheckBox: TCheckBox);
begin
with CheckBox do
if Checked then
if CreateEvent(nil, False, False, PChar(Format(‘Session\%d\MyAppEvent’, [Tag]))) <> 0 then
Caption := Format(‘Session %d event created’, [Tag])
else
Caption := Format(‘Session %d event creation failed, %s’, [Tag, SysErrorMessage(GetLastError())]);
end;
And then we can try to open the objects in other sessions:
procedure TForm1.OnOpenEvent(CheckBox: TCheckBox);
var
EventHandle : THandle;
begin
with CheckBox do
if Checked then
begin
EventHandle := OpenEvent(SYNCHRONIZE, False, PChar(Format(‘Session\%d\MyAppEvent’, [Tag])));
if EventHandle <> 0 then
begin
CloseHandle(EventHandle);
Caption := Format(‘Session %d event opened’, [Tag]);
end
else
Caption := Format(‘Session %d event open failed, %s’, [Tag, SysErrorMessage(GetLastError())]);
end;
end;
P.S. You can use this technique in any session for any object, which is created in the BaseNamedObjects directory: Event, Mutex, Semaphore, WaitableTimer, Job, FileMapping. Of course, security restrictions apply: you cannot create any object in another session if you do not have access to it. The LocalSystem account can create/access objects in any session, even idle sessions (which have not been initialized yet)
P.P.S. If terminal services are not running, the Session and \Sessions links are not created, so you cannot use them (but you can still use the Global and Local links, which are always created). Actually, there is no sense of using the Session\0\ prefix, since you can just use the Global\ prefix.
These are not the only places where you can create the kernel objects (Check part 2).
Related posts:
Active Directory Altiris bug Citrix Dell Delphi Exchange Exchange2003 Exchange2010 Hewlett-Packard HP iOS Jailbreak Java LinkedIn Linux MSI MySQL Navigation Objects Office Outlook Passat PowerPoint PowerShell referall was returned RNS315 RNS510 SasLibEx script slow Terminal Server ThinApp TSAdmin TSAdminEx VBS VCDS Vista VMWare Volkswagen Windows PE WLAN Wordpress WTSWaitSystemEvent wts_event_flush
WP Cumulus Flash tag cloud by Roy Tanck requires Flash Player 9 or better.
3 Responses for "Accessing kernel objects in other sessions part 1"
daNIL,
With this is it possible to rename a mounted easyprint printer to match a standard name (without redirect %session id%) ?
I have to hardcode printername in my application.
David,
Can you please tell me more about your problem? What are you trying to do?
[...] the post Accessing kernel objects in other sessions if you want to learn more about the Object [...]
Leave a reply