Window Stations & Desktops in .NET (1.)
Pokud netusite o co jde, prectete si dokumentaci na MSDN. Ve zkratce, kazda Windowsi session ma typicky jednu window station, ktera obsahuje clipboard a jeden ci vice desktopu. Desktop je logicka jednotka, ktera obsahuje procesy a jejich okna. Procesy v ruznych desktopech nemohou vzajemne ovlivnovat svoje okna (ie, nemuzou si posilat zpravy). Pomoci desktopu bylo odjakziva implementovane oddeleni screensaveru a logon UI od normalnich programu. Ve Viste je take pomoci jineho desktopu implementovany UAC prompt, takze zle aplikace v defaultnim desktopu nemohou programove odkliknout tlacitko "Continue" v UAC desktopu.
Ja bych se sice docela divil, kdyby to nekdo dalsi vyuzil; nicmene: .NET Framework neobsahuje API, ktere by k Window Stations a desktopum umoznovalo pristup, tak jsem si ho musel napsat. Ale muzete tento a nasledujici clanky brat alespon jako lehky tutorial k platform invoke (P/Invoke)...
V tomto prvnim clanku bych ukazal tridu, ktera mi vznikla jako base trida pro objekty popisujici jak window stations, tak desktopy. Jsou si totiz docela podobne: oba objekty maji jmeno, a lze je otevrit, cimz dostame od systemu handle, kterou bychom nemeli zapomenout zavrit.
Tady bych malinko odbocil. V .NETu 2.0 se objevila funkcionalita zvana SafeHandles, coz je samo o sobe zalezitost, ktera vyda na nekolik samostatnych clanku. Hlavni vyhodou je, ze drahy finalizator je na male tride, ktera zapouzdruje pouze a jen ten IntPtr (to je ta handle). SafeHandles jsou implementovane pomoci .NET 2.0 kritickych finalizatoru, u kterych runtime zarucuje, ze 1. budou opravdu zavolany (v pripade nasilneho unloadu AppDomeny), a 2. budou zavolany az PO vsech normalnich finalizatorech. Nehrozi tudiz situace, ze treba FileStream pri finalizaci flushne data do zavrene handle. Soubor se fyzicky zavre az v kritickem finalizatoru SafeHandle. P/Invoke take ref-countingem zajistuje, ze nedojde k zavreni handle, dokud bezi nejaka nativni funkce, ktera ji dostala za parametr.
Dale take finalizator SafeHandles pouziva CER blok, takze uzavreni handle se podari i v pripade stack overflow, abortnuti threadu, nebo jine osklive okolnosti.
Tohle vsechno nas v pripade window stations a desktopu az tak moc netrapi, ale SafeHandles muzeme pouzit i pro ne. Staci z odpovidajici tridy zdedit, poskytnout defaultni konstruktor, overridnout metodu ReleaseHandle, a pouzivat nasi tridu namisto raw IntPtr. Uvidite v druhem clanku.
Takze, nase base trida vypada nasledovne. Ma genericky parametr, ktery specifikuje typ SafeHandle, kterou bude podtrida zapouzdrovat, a pamatuje si svoje jmeno.
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace jachymko.Win32
{
public abstract class NamedNativeObject : IDisposable where THandle : SafeHandle
{
private readonly String _name;
private readonly THandle _handle;
protected NamedNativeObject(string name, THandle handle)
{
if (handle.IsInvalid)
{
throw new Win32Exception();
}
_name = name;
_handle = handle;
}
public void Dispose()
{
_handle.Dispose();
}
public string Name
{
get { return _name; }
}
protected THandle Handle
{
get { return _handle; }
}
}
}