WinSxS

Adresar WinSxS, ktery slouzi jako obdoba GACu pro unmanaged casti Windows, nemaji uzivatele moc radi: casto slycham dotazy jak jej promazat, ze pry je moc velky. Ale zdani klame. Vetsina souboru v nem jsou hard-linky jinych souboru, typicky v System32 nebo SysWow64. Jejich smazanim by se tudiz mnoho mista neuvolnilo, jedinym vysledkem by bylo rozbiti Windows Installeru a Windows Update a nasledna nemoznost instalovat programy a aktualizace. Pokud nekoho zajimaji cisla, muze pouzit prilozeny programek (netvrdim ze v nem nejsou chyby), ktery secte pocet a velikost souboru ktere maji vice jak jeden nazev. Na mych 64-bitovych Windows 7 Ultimate vraci tato cisla:

Total count: 39013
Total size: 6176613888

Hardlinked count: 20118
Hardlinked size: 4842450048

Unique size: 1334163840
Posted 21 January 09 09:30 by jachymko | 1 Comments   
Filed under ,
Attachment(s): sxs.txt
Gacutil Post-build Event
set PROCESSOR_ARCHITEW6432 >nul 2>nul

if ErrorLevel 0 (
    set NATIVE_PFILES=%ProgramW6432%
    set IS_WOW64=TRUE
) else (
    set NATIVE_PFILES=%ProgramFiles%
)

set BIN=%NATIVE_PFILES%\Microsoft SDKs\Windows\v6.0A\bin
set BIN64=%BIN%\x64

"%BIN%\gacutil.exe" /nologo /i "$(TargetPath)" /f

if (%IS_WOW64%) equ (TRUE) (
    "%BIN64%\gacutil.exe" /nologo /i "$(TargetPath)" /f
)
Posted 29 November 08 11:34 by jachymko | 0 Comments   
Filed under
BGShell

Po dlooooouhe dobe zkusim resuscitovat tenhle blog - napadlo me ze by nekoho treba zajimalo s cim si poslednich par mesicu hraju :) Dneska jsem dokoncil dalsi verzi interaktivniho PowerShell 2.0 hostu jmenem BGShell. Pokud ho budete chtit vyzkouset, nejprve si prosim nainstalujte Windows PowerShell 2.0 CTP2 a pote pokracujte na projekt na CodePlexu.

No a abych Vas trochu navnadil - co ta vec umi? Od minule verze obsahuje celkem solidni TabExpansion (ne takovy über-customizovatelny behemot jako je MOWova, ale rozhodne lepsi nez co nabizi standardni konzolovy host), samozrejmosti je moznost otevreni vice zalozek ci oken, syntax highlighting, podtrhavani chyb jako ve Wordu, a jako bonus "data tipy", podobne tem co znate z debuggeru Visual Studia 2005/2008.

Pokud stale jeste ctete tento post a neinstalujete, zkuste se tez kouknout na screencast od Hala R9000, ktery ukazuje nektere ficury.

http://CodePlex.com/BGShell/

Posted 24 June 08 02:05 by jachymko | 0 Comments   
Filed under
Jak ziskat jmeno uctu nebo skupiny ze SIDu?

Tridy NTAccount a SecurityIdentifier v .NETu 2.0 umoznuji pohodlne pracovat s uzivatelskymi ucty, skupinami a jejich SIDy. Obe tridy implementuji metodu Translate, ktera vyvori ze SecurityIdentifieru NTAccount a naopak.

Ukazeme si jak muze vypadat jejich pouziti. Nejprve vyjdeme z objektu WindowsIdentity, ktery predstavuje prihlaseneho uzivatele (Win32 security token). Ten ziskame statickou metodou GetCurrent():

$me = [Security.Principal.WindowsIdentity]::GetCurrent()

S timto objektem se uz daji delat zajimave veci. Jako prvni zjistime, ktery uzivatelsky ucet predstavuje. (Pokud by nas zajimalo jenom jmeno konkretni prihlasene WindowsIdentity, mohli bychom pouzit vlastnost WindowsIdentity.Name. Ale my chceme zjistovat jmena i cizich uctu) K tomu slouzi vlastnost User ktera vraci objekt typu SecurityIdentifier:

PS C:\> $me.User | fl

BinaryLength     : 28
AccountDomainSid : S-1-5-21-1721254763-462695806-1538882281
Value            : S-1-5-21-1721254763-462695806-1538882281-2421664

PS C:\> $me.User.GetType().FullName
System.Security.Principal.SecurityIdentifier
PS C:\>

Pomoci metody Translate ziskame ze SIDu odpovidajici NTAccount, ktery nam rekne jmeno uctu. Protoze objekt predstavujici tridu NTAccount budeme jeste za chvili potrebovat, ulozime si ho do promenne. Tato syntaxe, kdy je jmeno tridy v hranatych zavorkach pouzito jako samostatny vyraz, je ekvivalentni s C#ovym typeof(System.Security.Principal.NTAccount).

PS C:\> $NTAccount = [Security.Principal.NTAccount]
PS C:\> $me.User.Translate($NTAccount) | fl *

Value : EUROPE\jachymko

WindowsIdentity obsahuje krome hlavniho uzivatelskeho uctu i clenstvi ve skupinach. To muzou byt budto bezne Windowsi skupiny, nebo specialni skupiny jako treba LOCAL nebo INTERACTIVE, ktere predstavuji zpusob jakym byla dana WindowsIdentity vytvorena (jak se prihlasila). Vlastnost Groups opet vraci objekty typu SecurityIdentifier, takze pokud chceme znat jejich privetiva jmena, musime opet pouzit metodu translate. V tomto pripade vyuzijeme cmdlet Select-Object, ktery umoznuje snadno vytvaret nove objekty. Pokud misto nazvu vlastnosti zadate hashtable, ktera obsahuje klice N(ame) a E(xpression), vracene objekty budou obsahovat nove vytvorenou vlastnost s danym jmenem a spocitanou hodntou.

PS C:\> $me.Groups | sort BinaryLength | select Value, @{ N='Name'; E={ $_.Translate($NTAccount).Value } } | ft -a

Value                                             Name
-----                                             ----
S-1-2-0                                           LOCAL
S-1-5-4                                           NT AUTHORITY\INTERACTIVE
S-1-5-15                                          NT AUTHORITY\This Organization
S-1-5-11                                          NT AUTHORITY\Authenticated Users
S-1-1-0                                           Everyone
S-1-5-32-545                                      BUILTIN\Users
S-1-5-21-2127521184-1604012920-1887927527-572185  REDMOND\RAS_smartcard
S-1-5-21-2127521184-1604012920-1887927527-2115484 REDMOND\SQMUsers_CORP
S-1-5-21-1721254763-462695806-1538882281-4264     EUROPE\First Tier Domain Users
S-1-5-21-1721254763-462695806-1538882281-513      EUROPE\Domain Users
S-1-5-21-3410745329-1839241643-327782414-1000     MIJAVM\Debugger Users
S-1-5-21-1721254763-462695806-1538882281-2660054  EUROPE\Europe_ras_smartcard4
S-1-5-21-2127521184-1604012920-1887927527-1421044 REDMOND\Corp Users
S-1-5-21-2127521184-1604012920-1887927527-150552  REDMOND\prague

Vsechny predchozi priklady predpokladaly ze mame prihlasenou WindowsIdentity. Ale my muzeme mit treba jen jmeno nejakeho uctu, a chceme zjistit jeho SID. Neni nic snazsiho nez ze jmena uctu vytvorit NTAccount a z nej SecurityIdentifier. PowerShell ma oproti statickym jazykum zbudovane mnohem bohatsi castovani. Pokud trida ma TypeConverter, konstruktor ktery bere string, atd., tak PowerShell toho vyuzije. Existuji tri zpusoby jak lze castovat: budto explicitne cast pres hranate zavorky ve vyrazu:

PS C:\> $dbl = [double]"42.123456"
PS C:\> $dbl
42,123456

Nebo muzete typ napsat na levou stranu prirazovaciho vyrazu, cimz vytvorite strongly typed promennou. Vse co do ni priradite se bude automaticky konvertovat na jeji typ, pokud to bude mozne:

PS C:\> [double]$dbl = "84.2468"
PS C:\> $dbl
84,2468
PS C:\> $dbl = 'not-a-double'
Cannot convert value "not-a-double" to type "System.Double". Error: "Input string was not in a correct format."
At line:1 char:5
+ $dbl <<<<  = 'not-a-double'
PS C:\>

A poslednim zpusobem je operator -as. Ten se od predchozich zpusobu lisi jednak tim, ze vlevo je hodnota co se bude konvertovat a vpravo je cilovy typ, a druhak tim ze typ muze byt zadan za behu. Oba dva predchozi casty byly "natvrdo", v kodu skriptu je napsany dany type-literal, a na nej se vse prevede. S operatorem -as na prave strane klidne muze byt promenna, vyraz, nebo cokoliv. Muzete se zeptat uzivatele na co se ma hodnota prevest, a pokud takovy typ existuje, tak se tak stane. My to tady vyuzijeme, protoze uz mame ulozenou instanci predstavujici typ NTAccount, kterou jsme pouzivali s metodou Translate. Ted ji pouzijeme s built-in castovanim. Samozrejme, nic nam nebrani pouzit New-Object a explicitne zavolat konstruktor, ale toto je kratsi, zajimavejsi a mnohem vice l33t :-)

PS C:\> ('EUROPE\czmossvc' -as $NTAccount).Translate([Security.Principal.SecurityIdentifier]) | fl *


BinaryLength     : 28
AccountDomainSid : S-1-5-21-1721254763-462695806-1538882281
Value            : S-1-5-21-1721254763-462695806-1538882281-2803188
WOW64 File System Redirection

Michal psal ve svem zakysniku pred par mesici o systemovych adresarich v 64-bitovych Windows. Dovolim si ve zkratce zopakovat jak se chova System32: Microsoft nemohl pouzit pristup, ktery fungoval pri prechodu z Win16 na Win32, neboli pro 64-bitove knihovny udelat novy adresar system64, protoze spousta programatoru nedba dobrych rad, a za systemovy adresar povazuje (v lepsim pripade) %WinDir%\System32. Jeho zmena by prinesla vyrazny problem pri portovani aplikaci, ktere je jinak velmi primocare (Win16 a Win32 si byly, rekneme, "trosicku podobne", kdezto Win32 a Win64 je prakticky totez s jinou sirkou pointeru).

Resenim se stal File System Redirector, ktery vybrane adresare v 32-bit programech bezicich na 64-bitovych Windows presmerovava. Konkretne v opravdickem System32 jsou 64-bit knihovny, a v SysWOW64 jsou 32-bitove. WOW64 proces pak v System32 vidi obsah SysWOW64. Vetsinu casu toto funguje vyborne, ale obcas preci jen nejaky 32-bitovy proces potrebuje psat do opravdickeho, 64-bitoveho System32. Uz od prvnich Windows XP Professional x64 Edition byly k dispozici funkce Wow64DisableWow64FsRedirection a spol., ktere pro volajici thread redirektor vypnuly. To je sice hezke reseni pro 32-bitovy instalator, ktery potrebuje nainstalovat 64-bitove knihovny, ale pokud mate nejaky 32-bitovy program, ktery nemuzete zmenit (treba Visual Studio), a chcete v nem otevrit soubor v System32 (treba \Windows\System32\InetSrv\applicationHost.config), moc vam to nepomuze.

Pokud mate Windows Vista nebo Windows Server 2008, nemusite zoufat. WOW64 nyni podporuje takova zadni vratka, adresar SysNative, ktery v 32-bit procesech predstavuje 64-bitovy System32. Malou nevyhodou je, ze jelikoz jde o jakysi virtualni adrear, API pro vypisovani obsahu adrearu ho nevraci, a tudiz ani neni videt v common file dialozich. To se da ale snadno obejit kdyz v 64-bitovem procesu ten adresar vytvorite. Tim padem v 64-bitovych procesech bude prazdny, a v 32-bitovych procesech v nem uvidite obsah 64-bitoveho System32.

Posted 13 November 07 07:00 by jachymko | 9 Comments   
Filed under , , ,
PowerShell V2 CTP

Dnes vyslo prvni CTP pristi verze PowerShellu. Stahovat muzete na microsoft.com, co je noveho se dozvite na oficialnim PowerShell blogu. Mezi nejzajimavejsi novinky patri:

  • Remoting, implementovany pomoci WS-Management
  • Background Jobs aneb muzete poustet prikazy asynchrone
  • ScriptCmdlets umoznuji vytvaret plnohodnotne cmdlety v ps1 misto v kompilovanych jazycich
  • Graficky shell napsany ve WPF
  • Krokovatelne pipelines
  • a mnoho dalsich

Co me malinko zklamalo, je skutecnost ze V2 a V1 nelze provozovat side-by-side. Nova verze se stale instaluje do adresare v1.0, tudiz je potreba starou verzi pred instalaci odstranit. :-(

Posted 06 November 07 03:01 by jachymko | 0 Comments   
Filed under
UAC bez promptu

UAC je velmi sikovna vlastnost Windows Vista. Ale clovek obcas musi pouzivat i vyprasene programy, ktere vyzaduji admin prava pro svuj bezny provoz. Pokud vas nebavi pokazde potvrzovat UAC prompt, urcite ocenite nasledujici reseni: Scheduled Tasks umoznuji vytvorit ulohu, ktera vzdy bezi s administratorskym tokenem, i kdyz ji spusti bezny uzivatel. Uloha nemusi byt vubec "naplanovana", bude se spoustet pouze na vyzadani. Joel "Jaykul" Bennett ma prakticky PowerShellovy skript, ktery vytvoreni ulohy automatizuje:

http://huddledmasses.org/vista-setuid-how-to-elevate-without-prompting/

Posted 02 November 07 02:15 by jachymko | 0 Comments   
Filed under , ,
Dva programátoři v TV vědomostní soutěži
$ftip = @"
Dva programátoři v TV vědomostní soutěži:
Takže pane Jaroslave, pan Zbyněk dostal na papírku jméno osobnosti a vy máte hádat, 
kdo to je, a to jen pomocí otázek, na které Pan Zbyněk může odpovídat jen "Ano" nebo "Ne". 
Jaroslav: Jaké je jméno osobnosti kterou představujete? Zbyněk: 
Ne, ano, ne, ano, ne, ne, ano, ano; ne, ano, ano, ne, ne, ano, ne, ano; 
ne, ano, ano, ne, ne, ne, ano, ne; ne, ano, ano, ne, ne, ano, ne, ano; 
ne, ano, ano, ano, ne, ano, ne, ne; ne, ano, ano, ne, ano, ano, ano, ano; 
ne, ano, ano, ano, ne, ano, ano, ne; ne, ano, ano, ano, ne, ne, ano, ano; 
ne, ano, ano, ne, ano, ne, ano, ano; ne, ano, ano, ano, ano, ne, ne, ano.
"@

if ($ftip -match 'Zbyněk:([^\.]+)\.$')
{
	[Text.Encoding]::ASCII.GetString(
	$(
		foreach ($b in $( $matches[1].Split(';') |% { $_.Trim() } ))
		{
			$bits = $(switch( $b.Split(', ') |% { $_.Trim() } |? { $_ } )
			{
				'ano' { 1 }
		       		'ne'  { 0 }
			})

			
			0..7 |? { $bits[7-$_] } |% { $x = 0 } { $x += [Math]::Pow(2, $_) } { $x }
			write-debug "$bits = $x"
		}
	))
}
Posted 30 October 07 07:30 by jachymko | 2 Comments   
Filed under
Window Stations & Desktops in .NET (3.)

V predchozim clanku jsme napsali implementace SafeHandle, ktere zaobaluji handle k window station a k desktopu. Predtim jsme vytvorili base tridu, ktera si pamatuje jmeno a handle urciteho typu. Nyni je cas od teto tridy zdedit tridu, ktera bude predstavovat window station. Budeme ji modelovat podle WindowsIdentity a podobnych; konstruktor nechame privatni, jelikoz Win32 stejne neumoznuje vytvaret nove window stations. Misto toho vytvorime statickou metodu GetCurrent() a GetWindowStation(string name).

Nekoho by mohlo napadnout - proc delame metodu GetCurrent(), kdyz bychom mohli mit vlastnost Current? Metoda je v tomto pripade lepsi, protoze tim davame vic najevo, kdo je za zlikvidovani (disposnuti) instance zodpovedny. Mit vlastnost, ktera pri kazdem zavolani vytvari novou instanci, to je zverstvo. Takze pokud bychom sli cestou property, museli bychom instanci cachovat. To by mohlo prinest problemy s thread-safety (teoreticky, v pripade window stations asi ne; stejne s ni nemuzeme nic delat), a hlavne by porad nebyl jasny "otec", vlastnik objektu; instance by se pravdepodobne valela kolem az do unloadu AppDomeny. Proto jsem se rozhodnul imitovat WindowsIdentity spise nez treba HttpContext (u ktereho je, narozdil od tohoto pripadu, doba zivota presne dana zacatkem a koncem zpracovani pozadavku).

public sealed class WindowStation : NamedNativeObject<SafeWindowStationHandle>
{
    private const string Winsta0 = "Winsta0";

    private WindowStation(string name, SafeWindowStationHandle handle) : base (name, handle)
    {
    }

    public static WindowStation GetCurrent()
    {
        return new WindowStation(Winsta0, SafeNativeMethods.GetProcessWindowStation());
    }

    public static WindowStation GetWindowStation(string name)
    {
        return new WindowStation(name, OpenWindowStationRead(name));
    }

    private static SafeWindowStationHandle OpenWindowStationRead(string name)
    {
        return SafeNativeMethods.OpenWindowStation(name, false, GenericAccessMask.GenericRead);
    }
}

Takto sama o sobe je trida pomerne k nicemu. Potrebujeme dve hlavni metody; jednu, ktera nam rekne jmena vsech dostupnych window stations (i kdyz na stavajicich Windows se vam asi nestane, ze by tam byla jina nez Winsta0), a druhou, ktera nam rekne jmena desktopu v dane winsta. Obe metody jsou si podobne jako vejce vejci, pouzivaji anonymni metodu pro callback, ktera jmena hazi do Listu deklarovaneho ve "vnejsi" metode. Jeho obsah se pak vrati jako obycejne pole.

public static string[] GetWindowStationNames()
{
    List<String> names = new List<String>();

    EnumWindowStationProc callback = delegate(string winsta, IntPtr state)
    {
        names.Add(winsta);
        return true;
    };

    bool success = SafeNativeMethods.EnumWindowStations(callback, IntPtr.Zero);

    if (!success)
    {
        throw new Win32Exception();
    }

    return names.ToArray();
}

public string[] GetDesktopNames()
{
    List<String> desktopNames = new List<String>();

    EnumDesktopProc callback = delegate(string desktop, IntPtr state)
    {
        desktopNames.Add(desktop);
        return true;
    };

    bool success = SafeNativeMethods.EnumDesktops(Handle, callback, IntPtr.Zero);

    if (!success)
    {
        throw new Win32Exception();
    }

    return desktopNames.ToArray();
}

Posledni, co nam zbyva, jsou deklarace Win32 funkci ve tride SafeNativeMethods, spolu s delegaty a enumy. To vsechno naleznete v attachmentu tohoto postu, protoze jich je docela dost. Strucny popis atributu ReliabilityContract si muzete precist v minulem dile tohoto serialu.

Ted si jeste ukazeme jak tridu z PowerShellu zavolat:

PS C:\> $asmpath = 'D:\jachymko.Win32\bin\Debug\jachymko.Win32.dll'
PS C:\> [Reflection.Assembly]::LoadFrom($asmpath) | Out-Null
PS C:\>
PS C:\> $winsta = [jachymko.Win32.WindowStation]::GetCurrent()
PS C:\> $winsta

Name
----
Winsta0


PS C:\> $winsta.GetDesktopNames()
Screen-saver
testicek
Default
Winlogon
PS C:\> $winsta.Dispose()
PS C:\>
Posted 19 June 07 03:00 by jachymko | 0 Comments   
Filed under , ,
Attachment(s): SafeNativeMethods.cs.txt
Window Stations & Desktops in .NET (2.)

V predchozim clanku jsem ukazal base tridu pro nase pojmenovane nativni objekty. Nyni si napiseme implementace SafeHandles, ktere budou predstavovat Win32 desktopy a window stations. Protoze MSDN dokumentace k funkcim OpenDesktop, CreateDesktop, a ostatnim, rika, ze navratova hodnota NULL znamena chybu, zdedime nase tridy z SafeHandleZeroOrMinusOneIsInvalid, abychom nemuseli implementovat vlastnost IsInvalid. Jedine co se od nas ceka, je defaultni konstruktor a metoda ReleaseHandle. Konstruktor musi predat base tride flag ownsHandle, ktery urcuje, zda ve finalizatoru dojde k zavolani metody ReleaseHandle, coz je presne to, co chceme.

public sealed class SafeWindowStationHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    public SafeWindowStationHandle()
        : base(true)
    {
    }

    protected override bool ReleaseHandle()
    {
        return SafeNativeMethods.CloseWindowStation(handle);
    }
}

public sealed class SafeDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    public SafeDesktopHandle()
        : base(true)
    {
    }

    protected override bool ReleaseHandle()
    {
        return SafeNativeMethods.CloseDesktop(handle);
    }
}

Jak vidite, tridy pouzivaji metody CloseDesktop a CloseWindowStation, ktere mam nadeklarovany ve tride SafeNativeMethods. Ta momentalne vypada takto:

[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
    [return: MarshalAs(UnmanagedType.Bool)]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CloseWindowStation(IntPtr hWinsta);

    [return: MarshalAs(UnmanagedType.Bool)]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CloseDesktop(IntPtr hDesktop);
}

Tady je potreba si vsimnout dvou veci: prvni je atribut SuppressUnmanagedCodeSecurity, ktery zamezi generovani bezpecnostnich kontrol JIT kompilatorem, ktere by mohly selhat v pripade nedostatku pameti nebo stack overflow. Nam staci, ze Code Access Security engine overi pravo volat nativni kod pri naloadovani nasi assembly, a pri kazdem volani uz si to muze odpustit.

Druhou veci jsou atributy ReliabilityContract na metodach. Ty popisuji jak se metody zachovaji v pripade vyjimecnych podminek typu nedostatku pameti nebo mista na stacku. Parametr Consistency rika, v jakem stavu zanecha metoda objekt, appdomenu nebo proces. My autorum Win32 duverujeme, a spolehneme se, ze tyto metody v nenadale situaci neponici vubec nic. Druhy parametr, Cer, rika, zda metoda udela co se od ni ceka. To s jistotou tvrdit nemuzeme, nicmene obe metody vraceji false v pripade ze selzou, tudiz pouzijeme hodnotu MayFail. Ta znamena, ze metoda muze selhat, ale alespon nam to da vedet, a runtime zaruci, ze se mu podari vratit navratovou hodnotu. Oproti tomu hodnota Success znamena, ze metoda uspeje i v pripade vyjimecne neprijemnych podminek. To by mohl by pripad treba funkce Kernel32!CloseHandle.

Priste si ukazeme, co s temito handles muzeme udelat.

Posted 18 June 07 03:45 by jachymko | 0 Comments   
Filed under , , ,
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; }
        }
    }
}
Posted 18 June 07 01:30 by jachymko | 1 Comments   
Filed under , , ,
GhostDoc

Vynikajici addin do Visual Studia 2003-2008, ktery umi generovat XML komentare z (pochopitelne anglickych (a smysluplnych)) nazvu metod a vlastnosti.

Roland Weigelt's G h o s t D o c
Posted 15 June 07 06:00 by jachymko | 0 Comments   
Filed under ,
Trace-MsiInstallation

Zkousim prakticky nemozne, nainstalovat daily build Visual Studia 2008 na Windows Server 2008 Beta3. Uz tam mam i June CTP SQL Serveru 2008, ale .NET Framework 3.5 se ne a ne nainstalovat. A pres to nejede vlak. Protoze se to muze hodit i jindy, napsal jsem si podle navodu Aarona Stebnera jednoduchy skriptik, ktery zapne machine-wide logovani Windows Installeru, spusti instalaci a po skonceni vypise soubory ktere Windows Installer vytvoril v $Env:Temp. Mimochodem, kouknete na ten blog, zda se ze je tam vic uzitecnych informaci.

function Trace-MsiInstallation($path)
{
    Get-ChildItem $Env:Temp -Filter msi*.log | Remove-Item -Force -ErrorAction SilentlyContinue
	
    Set-Variable MsiPolicy HKLM:\SOFTWARE\Policies\Microsoft\Windows\Installer -Option Private,Constant 

    if (-not (Test-Path $MsiPolicy))
    {
        New-Item $MsiPolicy | Out-Null
    }
    
    Set-ItemProperty $MsiPolicy Logging 'voicewarmupx!'
    Set-ItemProperty $MsiPolicy Debug 7 -Type Dword
    
    $StartInfo = [Diagnostics.ProcessStartInfo] "$(Resolve-Path $path)"
    $Process = [Diagnostics.Process]::Start($StartInfo)
    $Process.WaitForExit()

    Remove-ItemProperty $MsiPolicy Logging
    Remove-ItemProperty $MsiPolicy Debug

    Get-ChildItem $Env:Temp -Filter msi*.log
}
ParseEnum

Vsichni zname metodu Enum.Parse, ktera vrati odpovidajici hodnotu enumu podle zadaneho retezce. Nevidim duvod proc v .NETu 2.0 neudelali jeji generickou verzi. Tak snad v nejake budouci verzi .NET 4.0. Zatim se musim spokojit s nasledujicim workaroundem:

private static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
    return (TEnum)Enum.Parse(typeof(TEnum), value);
}
Posted 12 June 07 04:00 by jachymko | 3 Comments   
Filed under
XmlSerializerConfigurationSectionHandler

Altair na aspnet.cz predloni napsal clanek Vytvoření vlastní konfigurační sekce ve Web.Config. Jedina nevyhoda toho pristupu je, ze clovek musi rucne psat konstruktor, ktery z XmlNode vytvori nas objekt. Protoze jsem prilis liny a nebavi me menit kod na spouste mist pokazde, kdyz chci pridat dalsi polozku, napsal jsem nasledujici tridu. Ta vyuziva XML serializace, takze trida drzici nase konfiguracni data je zaroven predpisem, jak je z app.configu nacist.

public abstract class XmlSerializerConfigurationSectionHandler<T> : IConfigurationSectionHandler where T : class, new()
{
    object IConfigurationSectionHandler.Create(object parent, object configContext, XmlNode section)
    {
        return serializer.Deserialize(new XmlNodeReader(section)) as T;
    }

    public static T GetConfiguration(string sectionName)
    {
        return ConfigurationManager.GetSection(sectionName) as T;
    }

    private static readonly XmlSerializer serializer = new XmlSerializer(typeof(T));
}

Pouziti je velice jednoduche. Nejprve si vytvorime oatributovanou tridu EmailSettings, ktera bude obsahovat nase konfiguracni data.

[XmlRoot("mailConfig")]
public class EmailSettings
{
    [XmlElement("from")]
    public EmailIdentity From;

    [XmlElement("to")]
    public EmailIdentity To;

    [XmlElement("smtpServer")]
    public string SmtpServer;

    public class EmailIdentity
    {
        [XmlAttribute("name")]
        public string Name;

        [XmlAttribute("address")]
        public string Address;

        public override string ToString()
        {
            return string.Format("\"{0}\" <{1}>", Name, Address);
        }
    }
}

A dale zdedime uplne primitivni tridu z XmlSerializerConfigurationSectionHandler, abychom do configu nemuseli vypisovat dlouhe jmeno genericke tridy:

public class EmailSettingsConfigSection : XmlSerializerConfigurationSectionHandler<EmailSettings>
{
}

Pro vetsi pohodli muzeme do tridy EmailSettings pridat statickou vlastnost Current, ktera zavola nas handler a vrati objekt pro nejakou defaultni sekci:

public static EmailSettings Current
{
    get { return EmailSettingsConfigSection.GetConfiguration("mailConfig"); }
}

A to je vse. Posledni co zbyva, je pridat nasi sekci do configu:

<configSections>
  <section name="mailConfig" type="jachymko.Blog.EmailSettingsConfigHandler, Test" />
</configSections>

...a poslat mail:

MailMessage mail = new MailMessage();
mail.From = EmailSettings.Current.From.ToString();
mail.To = EmailSettings.Current.To.ToString();
mail.Subject = "HA HA HA!";

SmtpClient smtp = new SmtpClient(EmailSettings.Current.SmtpServer);
smtp.Send(mail);
Posted 12 June 07 02:00 by jachymko | 4 Comments   
Filed under ,
Více článků Další stránka »