Windows II

Paměť

Pro Win16 bylo: lokální LocalAlloc( flags, size) (64K max.) nebo globální GlobalAlloc (max. 8000 alokací pro celý systém). Alokace nevracejí pointer ale Handle (umožňuje realokaci). Flags - fixed x moveable (pro fixed dostanu pointer a memory manager s pamětí nesmí hýbat, pro moveable: dostanu HGLOBAL/HLOCAL a pointer se dá získat pomocí LocalLock a vrátit LocalUnlock). Uvolňování - LocalFree, GlobalFree, ve Win16 povinné, jinak by došla paměť.

Ve Win32 alokují Local i Global na defaultním heapu aplikace (tj. už se neliší), obě používají HeapAlloc. new, malloc() z C++ jsou udělané pomocí Local/GlobalAlloc.

HeapAlloc( hHeap, flags, size ) - 1.par. - handle na heap (pro běžný proces: 1 heap, dá se zjistit: GetProcessHeap). Vrací pointer na alokované místo, HeapFree uvolňuje. Flagy: HEAP_ZERO_MEMORY - vynuluje paměť (ve Win32 nikdy v paměti nedostanu data cizího procesu, nanejvýš stará svoje); flag HEAP_NO_SERIALIZE - vypíná synchronizaci při alokaci, pokud není potřeba, zrychlí program. HeapRealloc - na starý pointer vrací nový, můžu zadat parametr HEAP_REALLOC_IN_PLACE_ONLY - když není místo, vrátí chybu.

Jiný heap v rámci mého 4GB adr. prostoru se dá vyrobit HeapCreate( flags, initSize, maxSize ) (a zrušit HeapDestroy). Víc užití, akorát mám-li víc pointrových struktur a nechci je poplést, nechci-li fragmentaci heapu (stejně velké kusy paměti do stejného heapu) - dobrý důvod předefinovat new. Zamykání haldy: HeapLock( hHeap ), HeapUnlock( hHeap ).

lpAllocated = VirtualAlloc( address, size, allocType, protect ) - alokuje na virtuálním adr. prostoru, kdekoliv i mimo heapy. Nízkoúrovňové, pro běžnou práci nevhodné. Používáno spec. fcemi jako CreateHeap. protect - kvůli data execution prevention, cpu caching, access guard. allocType - 2 příznaky: MEM_RESERVE - jen zablokuje, MEM_COMMIT - fakt alokuje. Mohu specifikovat adresu (NULL == je mi to jedno), pokud chci fakt alokovat tam kde mám paměť blokovanou; nebo při ukládání obrazu paměti na disk a zpět. Je pomalejší než HeapAlloc, který nealokuje fyz. pamět. Opak - VirtualFree. VirtualLock / VirtualUnlock - zakazuje odstránkovat z paměti. VirtualProtect - nastavuje/mění ochranu (stejně jako parametr protect u VirtualAlloc).

Mapování souborů

Slouží pro ukládání velkých dat. struktur; sdílení paměti 2 procesů!!! - zachází se s ním stejně jako se souborem na disku. Práce pomocí pointerů; při vytvoření spec. způsobem vůbec soubor nebude fyzicky na disku -> sdílená paměť.

Postup:

  • hFile = CreateFile( filename, access, share, secAttr, creationDisposition, flags, hTemplate )) ( flags - temporary, delete on close; creationDisposion - CREATE_NEW ).
  • hMapping = CreateFileMapping( hFile, secAttrib, maxSizeHi, maxSizeLo, name ) (neznám-li velikost souboru, stačí 0)
  • CreateFile vytvoří dat. strukturu popisující soubor; stejné pro existující soubory i logické soubory v paměti. Mapování svazuje kus paměti & soubor. Fce MapViewOfFile( hFile, access, offsetHi, offsetLo, bytes ) - z kterého souboru, kolik bajtů, odkud, MapViewOfFileEx - lpBaseAddress parametr navíc - kam do paměti se má soubor namapovat => mohu si uvnitř vytvářet spojáky, alokovat pamět apod., pak uložit na disk & po spuštění znova naalokuju tam kde byl minule.

    Pro sdílení mapování - OpenFileMapping - svázání se stejným souborem (musím zadat stejné jméno souboru jako 1.proces který zavolal CreateFileMapping). V novějších Win - CreateFileMapping se stejným názvem jako má existující mapování taky otevře (a následné volání GetLastError vrací ERROR_ALREADY_EXIST), pokud má právo, jinak selže. Pokud má soubor nastaveny flagy FILE_ATTRIBUTE_TEMPORARY a FILE_FLAG_DELETE_ON_CLOSE, nemusí vůbec dojít k zápisu na disk (pokud se paměť neodswapuje).

    Fce FlushViewOfFile synchronizuje paměť se souborem na disku, UnmapViewOfFile - zruší mapování. CloseHandle( hFile ) zavře mapovací soubor (nutné nejdřív zavřít všechna mapování a pak teprv soubor). Všechna mapování z 1 souboru jsou (kromě vzdálených souborů!!) identická v daném čase (zaručena koherence) - ale ne se stavem na disku (např. otevřeným ReadFile).

    TLS

    Thread Local Storage - ∀ proces tabulka 32-bit hodnot (řádky pro jednotl. vlákna), alokování & přidělování políček (sloupců). Sloupec se dá uchovat ve statické proměnné, jednotl. thready pak přistupují na svůj řádek v daném sloupci. Fce: dwIndex = TlsAlloc(), bSuccess = TlsFree( dwIndex), bSuccess = TlsSetValue( dwIndex, lpvoidValue ), lpvoidValue = TlsGetValue( dwIndex) . TlsAlloc vrací TLS_OUT_OF_INDEXES při neúspěchu. Délka pole: TLS_MINIMUM_AVAILABLE.

    Problém - jak zavolat alokaci - je třeba, aby ∀ fce měla jen 1 index -> nutné vyřešit před rozvětvením programu. DLL fce musí rozlišit, zda jsem ji volal poprvé (DllMain - switch( fdwReason ), case DLL_PROCESS_ATTACH) a tehdy alokovat v TLS. Nebo - na zač. dát statické proměnné neplatnou hodnotu - TLS_OUT_OF_INDEXES a testovat na ní; nutné semafory!.

    Používá systém pro např. fce strtok, asctime, gmtime (mezi voláním si musí pamatovat proměnné).

    Správa paměti

    V DOSu (80x86 real mode) - 2 části adresy: segment & offset (16bit). Použití segmentačního registru (nebo bázového & index registru) & offsetu, 1 adresový prostor (1MB). Protected mode (32 bit): logická adresa (32bit segment& 32bit offset) -> tabulka deskriptorů segmentů (globální/lokální/interruptová) - lineární adresa (VAP) -> tabulky stránek -> RAM. V programu - log. adresa = offset & registr (neobs. adresu segmentu, ale selektor = index do tabulky deskriptorů). Selektor = 16bit - 13bit index, 1bit GDT/LDT, 2bit - ring3/ring0(requested privilege level). GDT - pro celý systém, LDT - jedna pro každý proces.

    Win32 - "Flat memory model" - kód. & dat. segment začínají na 0x00000000, limit je 4GB -> offset == log. adresa == virt.adresa. Celá paměť je 1 segment, není ochrana na úrovni segmentace (až na úrovni tabulek stránek).

    Adresa GDT / LDT - dá se zjišťovat pomocí Kernel Debuggeru (nebo asm instrukcí), není furt stejné, liší se podle verzí Windows. Glob. tabulka deskriptorů - max. 128 položek; Glob. tabulka interruptů max. 256. Win32 vůbec nepoužívají LDT!

    Položky v tab. deskriptorů - báze: 32bit, limit 20bit, granularita 1bit (tj. segment může mít 1B - 1MB nebo 4KB - 4GB (granularita 1)), flagy existence, možnosti spustit/psát/číst, accessed flag, descriptor privilege level (ring3/ring0). Báze není na 1. místě -> nutno seřadit.

    Lineární adresa - 10bit "adresář tabulek stránek", 10bit tabulka stránek, 12bit offset; dohromady 32bit, 4KB - 1 stránka. Win95-ME - 2GB privátní prostor aplikace, 1GB sdílený prostor (R/W, obs. systémové moduly!! - pro DLL, Win16 aplikace), 1GB systém - ring0. NT+ - 2GB app, 2GB systém - ring0. (Win2000, Win2003 lze dělit i 3:1 ). Tabulky stránek samy se nacházejí v horních 2GB mého VAP.

    Stránkování

    Při natahování ze swapu do paměti - nejen 1 stránka, která chybí, ale pro kód 8 stránek, data - 4. Adr. prostor dělený na "clustery" po 8/4 stránkách, který stránku obsahuje, ten se natáhne do paměti. Vyhazování - Hodiny (vylepšené NRU) (pro multiprocesor Win neuměly až do XP -> FIFO) - lokálně pro 1 proces. Snaží se ∀ proces nějaké stránky udržet v paměti furt - min/max. working set (max. platí jen při startu programu, v případě potřeby se furt zvětšuje). V kernel debuggeru / assembleru se dají zjistit adresy tabulek stránek a číst je ( příkaz !process ).Page Table Entry - bity: valid, write, cache disabled, accessed, dirty atp., Page Frame Number (20bit) (+12bit offset = 4GB).

    System memory pool - systémový virt. prostor; část - nonpaged - nemůže být odstránkována (paged ano). Správa "volné" fyz. paměti - spojáky ukazující na odswapované stránky pro různé stavy stránek: modified (dirty - pro synchr. na disk), standby (ví se komu patřila, která je to stránka) <= "soft" výpadek, free (ví se komu patřila, ale ne která je to stránka - bezpečnost: stránku lze vrátit jen vlastníkovi), zero (nulované - čisté). Pro stránkování musí mít CPU přístup k adresáři stránek - musí znát fyzickou adresu!!.

    Pokud sáhnu na fyzicky nenaalokovanou paměť - v normálním režimu pád aplikace, kernel: BSoD! Zjištění zda je něco naalokované - přímo číst tabulky stránek (s pomocí driveru na ringu0 přečíst obsah 80x86 registru cr3 - fyz. adresa adresáře stránek), pokus o alokaci na dané adrese (jde -> nic tam není/nejde -> můžu číst) - nelze (alokace se zarovnávají na "kulaté" adresy - pokud je alokováno něco kus vedle, nemůžu alokovat už tady). Fce BOOL IsBadCodePtr( address, size ) , IsBadReadPtr , IsBadWritePtr - (podle MSDN) info o naalokované paměti. Pro popis naalokované virtuální paměti - systém udržuje Virtual Address Descriptors (vyvážený binární strom) (využívaný VirtualAlloc -obs. i nenaalokované, jen rezervované bloky!!; výpis - VS.NET tool VaDump.exe).

    Procesy a vlákna

    Spuštění nového programu - WinExec( LPCSTR cmdLine, UINT nCmdShow ) - nCmdShow - má být vidět? SW_HIDE = neviditelné (pomocná aplikace - má okno, které není vidět, mohu mu posílat zprávy). Jiné - LoadModule( name, parameters ) - v params (LOADPARMS32) mohu nastavit jiný environment: (GetEnvironmentString()); (LoadModule je podle MSDN obsolete, má se používat CreateProcess, který toho umí víc).

    CreateProcess - od Win95. Lze i spustit pod jiným uživatelem: CreateProcessAsUser, LogonUser - vrátí parametry potřebné pro CreateProcessAsUser (ale heslo nešifrovaně dostane moje aplikace => uživ. nemusí důvěřovat). Varianta - CreateProcessWithLogon - to samé. CreateProcess( name, cmdLine, processSecAttrib, threadSecAttrib, boolInheritHs, flags, environment, curdir, startupinfo, &processinfo ): jméno programu, zbytek přík. řádky (odděleně) - POZOR! spojí si to & exe soubor hledá mechanicky odleva - "C:\program files\program" může spustit "C:\program.exe" pokud existuje => pro jméno programu nutné použít uvozovky! CreateProcess vrací handle na proces, handle na 1. thread a ID obojího. Další parametr: flagy - lze nastavit třídu priority: REALTIME_PRIORITY_CLASS, IDLE..., NORMAL... . STARTUPINFO: větš. věcí pro nastavení konzolové aplikace: velikosti oken, souřadnice, flagy (co z nastavených použít?), viditelnost okna (v ShowWindow - ignoruje se parametr 1.volání v procesu a okno se zobrazí jak já nastavím) (u ostatních případů to aplikace dostane jako parametr WinMainu). Spuštění & zobrazení okna apod. chvíli trvá - mohu mezitím dostat procesor a snažit se o komunikaci -> pozor!.

    SECURITY_ATTRIBUTES (pointer na strukturu): obs. nLength - sizeof(), securityDescriptor - ovládá sdílení& práva (tajná struktura :), obs. info o vlastníkovi, skupině, access control listy (seznam objektů s povoleným/zakázaným přístupem); inheritHnadle - je možné aby další procesy nově vytvořené mým programem mohly používat handle na akt. vytvářený proces? (může být NULL).

    Ukončení procesu: ExitProcess( int exitCode ) - skok na konec programu, ale korektně: zavře soubory, odpojí DLL apod. Jde jen pro moje procesy. TerminateProcess( HANDLE hProcess, UINT fuExitCode ) - killne pomocí handle na proces (hlavně pro child procesy). Skončí taky správně, ale DLL odpojí násilím!, pokud ty měly otevřené soubory pro proces, nezavřou se; ve Win16 se ani neodalokovala paměť (Win32 OK). Při ukončování: ukončí se vlákna, zavřou handly, signalizuje se konec a stav. info se změní na exitcode. Pokud mám handle, mohu testovat i zda proces už skončil - GetExitCodeProcess( hProcess, lpExitCode ); mohu se ptát neomezeně dlouho po skončení, mám-li handle (proti konstantě STILL_ACTIVE).

    HINSTANCE ShellExecute( hOwnerWindow, operation, filename, parameters, directory ) - lze spouštět i datové soubory (spustí se v jim přiřazeném programu). Mohu s nimi vyvolat libovolnou operaci pro daný soubor (musím ale vědět, jak se jmenuje). Varianta ShellExecuteEx - spousta parametrů (show, hIcon - ikona - VJJ neví jestli se fakt dá změnit).

    Thread

    Vytvořím hThread = CreateThread( secAttr, stackSize, startFce, param, flags, &threadId ) , v parametrech: fce která ho spouští - spec. tvar - DWORD WINAPI fce( LPVOID param ); security attributes - stejně jako pro proces; velikost stacku (default: 1M); nazpět dostanu handle & id vlákna. Končí se stejně jako proces: ExitThread (sebevražda), TerminateThread (vražda - i pro vlákna cizích procesů, mám-li handle); ∀ vlákno navíc může zabít celý proces.

    Vlákna - foregroundová & backgroundová. Žije-li ≥ 1 vlákno, proces se nekončí (bacha CRT volá ExitProcess pokud končí hlavní vlákno ("some implementations", i MSVS.NET2005)). Fg/bg se liší jen tím že fg mohou vlastnit okna. Pokud vyrábím fg vlákno, musí mít vlastní message loop! - jak vyrobí okno, dostane vlastní message queue. Fg vlákno se stane fg vláknem až tehdy, když vytvoří okno!

    Vlákna v .NET

    using System.Threading; Thread t1 = new Thread (new ThreadStart( Trida.Fce ) ); - vytvoření vlákna. spuštění - t1.Start() , čekání na vlákno - t1.Join(); . Dotaz na běžící vlákno: t1.IsAlive(); , na backgroundové - t1.IsBackground(); - to je vlastnost, která lze měnit! nemá ale jiný význam než "chcípnou-li backgr. vlákna, chcípne proces." Jméno vlákna - t1.Name - write-once property. vlákna lze hledat podle id nebo mnou nastaveného jména.

    Priorita - mění se vlastnost t1.Priority = ThreadPriority.AboveNormal . lze pozastavit, oživit: t1.Suspend() , t1.Resume(); , zjišťovat přes t1.ThreadState == ThreadState.Running atp. Změna uživatele - thread.CurrentPrincipal = new GenericPrincipal( ... ) - nastavím pod jakou rolí (.NET) běží proces; použití - např. webserver.

    V .NET neex. možnost spustit proces pod uživatelem (LogonUser), ale jde includovat ze std. WinAPI (není ale bezpečné - .NET nemůže hlídat)- "p/invoke". [ DllImport( "advapi32.dll", SetLastError=true) ] & hlavička fce - static extern int LogonUser( .... ) . Místo handle získám voláním fce ".NET token", použitelný v jiných fcích: WindowsIdentity wi = new WindowsIdentity( token ); WindowsImpersonationContext wic = wi.Impersonate; ..., konec impersonace: wic.Undo(); . Toto je oficální návod, podle VJJ nefunkční. Navíc pro běh nutné mít privilegium SE_TCB_NAME (v group policy se dá nastavit jako "Act as part of the OS").

    Střídání procesu

    Časová kvanta - default 6 (workstation), 36 (server), po ticku (1x/10ms - 1CPU, 1x/15ms - SMP) procesoru se od kvanta odčítá 3 (dá se v registrech měnit). Priorita - 32 levelů, horní půlka - "real-time" (jen název, Win není RT-OS); normal == 8 (± 1). Fronty ∀ prioritu, problém - zmrzání systému při náročných aplikacích (WinNT: foregroundové okno mělo o 2 vyšší prioritu, takže se k CPU prakticky nic jiného nedostalo), dnes (Win2000+): dynamická kvanta (dají se nastavit: variable/fixed (zvýhodnit/nezvýhodnit procesy na popředí), long/short(dlouhá/krátká kvanta), fg quantum boost (o kolik zvýhodnit proces na popředí- pro každou kombinaci variable/fixed a long/short je tabulka o 3 položkách, fg quantum boost udává kterou položku používají fg okna, bg okna používají 0. položku vždy) ).

    START program.exe /NORMAL (/REALTIME - nutné uživ. právo increase scheduling priority) - spuštění s jinou prioritou (správce může kompletně zablokovat). V programu - GetPriorityClass( hProcess ) , SetPriorityClass( hProcess, dwPriority ) ( IDLE_PRIORITY_CLASS ... ) - můžu se ptát/nastavovat cokoliv na co mám handle. Priority vláken - GetThreadPriority, SetThreadPriority, je v závislosti na prioritě procesu; konstanty: THREAD_PRIORITY_IDLE, LOWEST ... , TIMECRITICAL . Jde nastavit i nezávisle na procesu ale nepoužívá se, typické použití - backg. thready mají o 1 méně. Uspání vlákna - SuspendThread , probuzení ResumeThread ; uspání mého vlákna na danou dobu - Sleep .

    Priority boost - zvýšení priority o nějakou hodnotu, postupně po 1 se vrací na base - po ukončení I/O operací(base+1) nebo čekání na semafor(+1)/objekt jádra(current!+prioritySeparation(=0,1,2), po aktivaci okna (+2), thread starvation (bez CPU 4sec.) (priority := 15, 2x - 4x delší kvantum, HNED zpět)

    Preemptivní multitasking - spouští se když thread začal čekat, vyčerpal kvantum, skončil; nebo pokud skončil čekání důležitější thread/ priorita threadu byla změněna. Přeplánování, když thread je připraven / opustil running state / změnila se priorita / změnila se CPU-afinita. Dispatcher database = seznam procesů, k nim jejich thready & seznam připravených threadů ∀ prioritu. Idle thread - imaginární priorita 0, povoluje a zakazuje interrupty, spouští Deferred Procedure Call (dispatcher/rescheduling), spouští standby thread (předvybraný) / processor idle routine (power management).

    V kernelu jsou uchovávány proměnné jako bit-maska aktivních procesorů, bitmaska priority levelů s ready vláknem atd. Navíc ∀ proces: dat. struktura EPROCESS - executive process block ( údaje o procesu a jeho vláknech), ten obs. KPROCESS (kernel p.b. pro informace týkající se jádra/plánování ) a PEB (process environment block - info pro DLL, TLS, je v paměti procesu, přístupný z ring3, narozdíl od ostatních) a další: working set info, virtual memory info(atp.) ... . Podobně pro thread - ETHREAD, KTHREAD, TEB. ETHREAD - obs. odkaz na EPROCESS, I/O na které čeká; KTHREAD - scheduling info (priority, quantum...), execution time, seznam kernel mutexů(mutant), wait block (seznam objektů na které čeká). TEB - TLS array, User32/GDI32/OpenGL info, locale atd.

    Systém souborů

    GetLogicalDriveStrings( nBufLenght, lpBuffer ) vrací seznam disk. jednotek v počítači (string, oddělený #0, na konci #0#0 ). dwMask = GetLogicalDrives() - vrací bitovou masku (32-bit); GetDriveType("C:\") - vrátí typ jednotky (1 == neexistuje (občas nefunguje!), 0 == nelze určit). GetVolumeInformation( rootPath, nameBuf, nameBufSize, &serialNo, &maxFilenameLenght, &flags, fileSystemNameBuf, fsNameBufSize ) - vrací: label, serial number, filesystem name (důležité!) atd.. GetDiskFreeSpace - vrací volné místo na disku.

    DeviceIoControl - důležitá fce, umožňuje dělat s diskem cokoliv (low-level, parametr controlCode - podle něj odp. akce, hDevice). Další fce: CreateDirectory, CopyFile, MoveFile - jen uvnitř 1 log. disku (MoveFileEx - i mimo, dá se nastavit COPY_ALLOWED ). Nelze používat wildcardy.

    CreateFile - vytvoří soubor; parametry: lpPathName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition (CREATE_NEW - failne když soubor existuje, CREATE_ALWAYS, OPEN_ALWAYS - když neex., vytvoří nový, OPEN_EXISTING - když neex., failne, TRUNCATE_EXISTING ), dwFlagsAndAttributes ( FILE_ATTRIBUTE_TEMPORARY, FILE_FLAG_DELETE_ON_CLOSE, RANDOM_ACCESS, SEQUENTIAL_SCAN FILE_FLAG_OVERLAPPED ), hFileTemplate (specif. rozš. atributů == NULL).

    Čtení ze souboru - ReadFile( hFile, lpBuffer, dwBytesToRead, lpdwBytesRead, lpOverlapped ) , sekvenční - default - lpOverlapped == NULL; vrací výsledek - BOOL. WriteFile - s přímým přístupem lze psát i za koncem souboru (potom musím ale přenastavit konec souboru, nebo o data při zavření přijdu, do zavření tam data jsou), podobné jako ReadFile.

    SetFilePointer( hFile, lDistance, lplDistanceHigh (fakt pointer!), dwMoveMethod) == seek., dwMomeMethod - FILE_BEGIN, FILE_CURRENT, FILE_END; adresováno 64 bity => potřebuju 2 parametry. SetEndOfFile(hFile) - nastaví konec souboru na akt. pozici, CloseHandle - zavře. zamknutí části souboru - LockFile( hFile, offsetLo, offsetHi, bytesLo, bytesHi ), UnlockFile - lze sdílet mezi vlákny (moc se nepoužívá).

    Struktura OVERLAPPED - pro Read/WriteFile - pro její použití je nutné při CreateFile mít zapnutý flag FILE_FLAG_OVERLAPPED, používá se mj. pro paralelní čtení a zápis; obs. 64-bit adresu odkud se čte - Offset, OffsetHigh; Internal, InternalHigh, Pointer - musí být nula; hEvent - událost pro synchronizaci (nastavena po skončení operace). Pro paralelní čtení a zápis nutné otevřít soubor s přímým přístupem, jinak dělá bordel ukazovátko.

    NTFS

    Místo FAT - Master File Table : 1024 B / 1 položka tabulky (je-li soubor krátký jeho data jsou zde). Jinak obs. standardní atributy (RAHS, čas vytvoření, změny, přístupu), jméno (Unicode), security descriptor, data (nepojmenovaný stream), pojmenovaná data; index root& index allocation bitmap (pro velké adresáře - jen adresáře), reparse (systém. filtr spouštěný při každém přístupu).

    Uvnitř souboru - mohou být streamy - několik různých proudů dat; default: nepojmenovaný. dá se do nich psát/číst, defaultně nejsou vidět ( echo "text" > soubor.txt:jmeno_streamu ), soubor má udávanou velikost defaultního streamu, ale na disku může zabírat víc. CreateFile( "file.txt:stream" ); sizeLow = GetFileSize( hFile, &sizeHi ) - pokud dám handle na pojmenovaný stream, zjistí jeho velikost; bez udání streamu vrátí velikost defaultního. CopyFile( sourceName, targetName, bFailIfExist - bez udání streamu kopíruje celý soubor. Pokud je 1 parametr stream, týká se jen streamů (2. neudaný == defaultní), ale pokud cíl. soubor existuje, smaže se CELÝ. Default stream do default streamu je složité kopírovat.

    Mazání v 1 streamu - SetFilePointer( hStream, 0, .. ), SetEndOfFile( hStream ) - smaže data ve streamu, ten furt existuje s nulovou velikostí. DeleteFile( "file.txt:stream" ) - smaže stream (není-li udaný, celý soubor). Zjištění existence streamů - nejde moc dobře - fce BackupRead načítá co nejvíc informací o souboru, mj. i jména streamů (cyklení funkce dokud nevrátí false). Existuje pro to utilita ve Windows Resource Kitu.

    Komprese - lze komprimovat soubory i adresáře. Zapnutí - lze zjistit zda NTFS verze podporuje (GetVolumeInformation a flag FS_FILE_COMPRESSION), zapnout: DeviceIoControl( hFile, FSCTL_SET_COMPRESSION ) , lze se ptát zda je komprimovaný - dwAttrib = GetFileAttributes( filename ) - atrib & FILE_ATTRIBUTE_COMPRESSED; jinak přes GetFileInformationByHandle, DeviceIoControl. Velikost - GetFileSize - velikost dat, GetCompressedFileSize- na disku. Komprese - soubor se čte po 16 clusterech, poslední blok se jen zkopíruje, nekomprimuje!!!.

    Řídké soubory - sparse streams: neukládá nuly; používá taky 16 clusterů - buď vypustí 16 clusterů nebo nic. Musí se nastavit : DeviceIoControl( FSCTL_SETSPARSE ) , ale systém sám neudělá, je nutné mu explicitně říct kde jsou nuly! (DeviceIoControl( ...FSCTL_SETZERODATA ... )), důležité, aby úsek nul zabíral 16 clusterů, a říct NAJEDNOU že jde o 16+ clusterů (2x 8 vedle sebe nefunguje). Lze tak i vytvořit soubor větší než disk (pokud nastavím soubor jako sparse, pak dám SetFilePointer( ... ) a zavřu) - pak problémy s backupem! Místo zabrané se mění naprosto nezávisle s růstem imaginární velikosti. Dá se ptát i jestli je soubor řídký; použít jako primitivní ochranu dat - pár TB nul před skutečnými daty.

    Šifrování - z Win2000 jde z promptu ( cipher /e adresar, cipher /d adresar ); API-fce: EncryptFile, DecryptFile (2. parametr - algoritmus - se zatím nepoužívá -> 0 ). Dá se i testovat možnost šifrování na daném filesystému (GetVolumeInformation - atrib & FILE_SUPPORTS_ENCRYPTION); šifrovanost daného souboru - GetFileAttributes, attrib & FILE_ATTRIBUTES_ENCRYPTED . Algoritmus - DES/3DES (M$ varianta).

    Synchronizace

    Prostředky - WinAPI

    Lze jednoduše: HANDLE hKonec = CreateEvent( NULL, true, false, "" ); , SetEvent( hKonec ); , WaitForSingleObject( hKonec, INFINITE ); - podle MSDN pasivní čekání, nežere CPU. Jednodušší způsob - HANDLE hVlakno = CreateThread( ... ); WaitForSingleObject( hVlakno, INFINITE ); - vlákno/proces je synchronizační objekt, na něž lze čekat, dokud neskončí. Lze čekat i na asynchronní čtení ze souboru - ve WaitForSingleObject jen dám handle na soubor (ale jen pro jednodušší případy - čte-li se víckrát souběžně z 1 souboru, po skončení lib. čtení projde; lze ale nastavit i completion routine v ReadFileEx (nevrací počet přečtených bajtů, navíc parametr - pointer na FileIOCompletionRoutine funkci, která je zavolaná na konci operace (parametry: errCode, bytesTransferred, overlapped)) - a použít WaitForSingleObjectEx( hEventvOverlapped, milis, bAlertable == TRUE ) <- pokud posl. parametr je TRUE, volá se CompletionRoutine, jinak čekání neprojde ).

    Synchronizace = ochrana krit. sekcí v procesech (instrukcí pracujících se sdílenými daty). Fce Wait, Release - vstup, výstup z krit. sekcí. Jde více způsoby:

  • WaitForSingleObject( HANDLE hSemafor, DWORD limitMilisec ) - limit může být i 0 (vůbec nečeká), nebo konstanta INFINITE. Návr. hodnota - WAIT_OBJECT_0 - OK, WAIT_TIMEOUT - konec čekání, WAIT_ABANDONED - opuštěný semafor (jeho thread skončil), WAIT_FAILED - systémová chyba. Konec fce WaitForSingleObject za sebou sklopí semafor.
  • Pro víc objektů: WaitForMultipleObjects( dwPocet, lphObjects, boolWaitAll, dwMilis ) - waitAll - čekat na všechny, nebo na 1 libovolný? Počet objektů nesmí být víc než MAXIMUM_WAIT_OBJECTS. Návr. hodnota = ( WAIT_OBJECT_0 + kolikátý handle prošel ).
  • WaitForInputIdle( hProcess, dwMilis ) - čekám, dokud proces nemá prázdnou frontu zpráv; pak mohu např. žádat handle na otevřené okno a posílat mu zprávy.
  • kombinace: MsgWaitForMultipleObjects( dwPocet, lpHandlesArray, boolWaitAll, dwMilis, dwWakeMask ) - wake mask - na které typy zpráv se čeká. Čeká se na objekty specifikované v handlesArray a/nebo na přijití zpráv specifikovaného typu do fronty a/nebo nebo daný čas. interval. ( dwWakeMask: QS_ALLINPUT, QS_INPUT, QS_POSTMESSAGE, QS_TIMER, QS_PAINT, QS_SENDMESSAGE ... )
  • Pro práci s krit. sekcí - v systému jsou semafory. M$ má semafory 2 typů. HANDLE hSemaphore = CreateSemaphore( lpSecurityAttr, lInitValue, lMaxValue, lpszName ) - vícehodnotový; podle max. počtu procesů v krit. sekci paralelně; při čekání - záporný = počet čekajících. Pokud dám MaxValue = 1, jde o klasický binární semafor. Přístup k již vytvořenému semaforu: OpenSemaphore( dwDesiredAccess, bInheritHandle, lpszName ) přístup - běžně: SEMAPHORE_ALL_ACCESS; lze i jen pro release nebo jen pro Wait. Vrací handle. ReleaseSemaphore( hSemaphore, longOKolik (> 0), lplong Puvodni ) - zvedá semafor (může o víc než 1!), lze volat i aniž bych semafor sklopil (můžu vyřešit, když umře vlákno které ho spustí - ale nebezpečné). Mám-li víc vláken, hSemafor může být glob. proměnná, ale pro víc procesů musím použít OpenSemaphore (nebo od Win2000 CreateSemaphore otevře existující, neupraví MaxValue ani InitValue, následné volání GetLastError vrací ERROR_ALREADY_EXIST ). Jména semaforů jsou globální pro celý OS --> může dojít ke kolizi 2 programů.

    HANDLE hMutex = CreateMutex( lpSecurityAttr, bInitialOwner, lpszMutexName ) - je normální binární semafor (v kernelu == "mutant"); lze taky pojmenovat, pokud je InitialOwner == TRUE, pak je od zač. spuštěný, moje vlákno je vlastníkem. Zvednout může JEN vlákno které ho sklopilo ( ReleaseMutex( hMutex ) ) - nelze zvnějšku; kvůli tomu ex. návratová hodnota u WaitFor... - WAIT_ABANDONED. Stejně jako pro semafory existuje i fce OpenMutex() ale už není potřebná.

    Semaphore i Mutex (a cokoliv) se ruší funkcí CloseHandle .

    .NET

    Mutex - std. třída (System.Threading) : static Mutex m = new Mutex; m.WaitOne( Timeout.Infinite, false ); m.ReleaseMutex();, víc mutexů lze dát do pole: Mutex.WaitAll( Mutex [] ); Mutex.WaitAny(); , pro WaitAny se musím znova pomocí WaitOne( 0, false ) ptát co prošlo.

    Způsoby synchronizace

    Ve WinAPI - na synchronizaci vláken 1 procesu - lze použít kritickou sekci: CRITICAL_SECTION cs; , InitializeCriticalSection( &cs ); , EnterCriticalSection( &cs ); , LeaveCriticalSection( &cs ); - uvnitř funguje stejně jako mutex, jen jiné volání. Ale jen v rámci 1 procesu!!!.

    Jiné - wait&signal: Lze udělat pomocí semaforů (vytvořený zavřený, po události otevřený), ale i jinak: HANDLE CreateEvent( lpSecurity, bManualReset, bInitialState, lpszName ) - bManualReset: ručně x automaticky ovládané: je-li manuální, zůstane projitím waitu event nastavený, lze zrušit manuálně: ResetEvent();. Získání handle na existující event: OpenEvent() (nebo CreateEvent, podobně jako u semaforů). SetEvent() - nastaví událost. PulseEvent(); - při automatickém resetu pustí 1. čekajícího, pro manuální všechny, zruší nastavení eventu (pomocí semaforu moc dobře nejde - během pouštění se mohou řadit do fronty další, ti už neprojdou). Pořadí vláken ve frontě není zaručené!

    v .NET stejně jako ve WinAPI - třídy AutoResetEvent, ManualResetEvent , metody: .Set(), .WaitOne(), .Reset() . Není ale Pulse! (lze udělat pomocí Monitoru). Pro práci se sdílenými daty: Monitor / Zámky - Monitor.Enter(buffer), Monitor.Exit(buffer), lock (buffer){ ...kód kritické sekce... } - v C#. Monitor umí i pulse: Monitor.Pulse( buffer ), Monitor.PulseAll( buffer ).

    DLL

    Statické linkování = tabulky ext. referencí, pokrývání symbolů - při překladu (je tranzitivní). Dynamické linkování - hInstanceDLL = LoadLibrary( "library.dll" ) , lpfnFunkce = GetProcAddress( hInstanceDLL, "JménoExportovanéFunkce" ) , lpfnFunkce = GetProcAddress( hInstanceDLL, MAKEINTRESOURCE( PořČExpFce )) , FreeLibrary( hInstDLL ), hModuleDLL = GetModuleHandle( "library.dll" ) . Program je staticky slinkován s exportní knihovnou library.lib, library.dll je namapována do adres. prostoru hned při inicializaci. 2 způsoby: při loadování hned přepsat všechny odkazy na fce z DLL správnou adresou (pomalý start aplikace), nebo LIB obsahuje už instrukce skoku na požadované fce (tj. při jejich volání - 2 instr. skoku; při nahrání DLL na jinou než defaultní báz. adresu jdou upravit).

    Export fcí v C++ - jména zahrnují i počty & typy parametrů -> paznaky, složitosti ("name mangling"). DLL - má vlastní DllMain: BOOL WINAPI DllMain( hInstDll, fdwReason, lpvReserved ) - v něm: switch( fdwReason ) , case DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, DLL_PROCESS_DETACH - proběhne správně jen pokud DllMain vrátí TRUE (tj. při chybě vrátit FALSE a nahrání DLL selže).

    Soubory .DEF - informace pro linker o exportovaných fcích (není nutné - lze použít parametry linkeru, nebo MSVS .NET). Obs. klauzule LIBRARY jmeno_dll, EXPORTS - seznam fcí. ; - komentář. 1 export. fce: Name [= InternalName ] [@cislo_export_fce [NONAME - export jen pod číslem]] [PRIVATE, DATA, CONSTANT]. Export se dá zařídit i pomocí _declspec( dllexport ) klauzule (ale jen pro C funkce - použít extern "C", C++ dělá problémy).

    V .NET - namespace myDLL, public class; public fce -> exportování fce.

    Kernel

    Struktura

    Přechod do Kernel módu - device driver/ OS function. Unhadled exception = memory access violation. Volání fcí jádra - pořadí důležitosti: IRQL (interrupt request level), nejvíc - hardware, potom software (DPC/Dispatch, APC), nejmíň: norm. programy (passive). Page fault: DPC/Dispatch nebo výš. Std. fce na shození Windows - KeBugCheckEx( 0xDEADDEAD,... ). Lze vyrobit bluescreen na přání editací registrů - CrashOnCtrlScroll, ve Win2000 ukončením csrss.exe, z driveru: při instalaci return *((NTSTATUS *)0);.

    Struktura Win2K+:

  • kernel: ntoskrnl.exe, obs. system service dispatcher: reaguje na požadavky aplikací, zjišťuje kterou fci má zavolat. pod ním - executive: obs. funkce (system services) - exportované/neexportované. nejníž - kernel, device drivers. vedle - přímo na na HW: ovladače grafiky, nad nimi win32k.sys (Win32, USER, GDI) - nově ve Win2000 - zrychlení (dřív "environment subsystems" na user mode, přepínání ring3/0 pro každou fci.) win32k.sys - Window manager, správa vstupu z kláv.,. myši, řízení výstupu na obrazovku. Pod kernelem - HAL - hardware abstraction layer.
  • user: zbytky environment subsystems - csrss.exe - stará se hlavně o zakládání nových procesů, konzolové aplikace. mezi aplikacemi a jádrem: subsystem DLLs (kernel32.dll, advapi32.dll, user32.dll, gdi32.dll) a pod nimi ntdll.dll - větš. zařídí jen přechod do jádra a zavolání 1 fce - pomocí instrukce SysEnter (od PentiumPro a WinXP; int 2E pro Win2000 a NT) - volání stejně pojmenované fce z ntoskrnl.exe; sdružuje hlavní API-fce (200+). obs. C-runtime library, heap manager atp.
  • Přechody ring3 <-> ring0

    Pro vyhledání - debugger: windbg.exe (stáhnutelný z microsoft.com) pro normální i kernel debugging (vždy se ale připojuje k jádru, aby byly vidět symboly). Připojení k procesu - "Attach to a process..." noninvasive. příkazy: ln - "locate next", u - výpis (instrukcí fce), d - dereference. Pro pohled do DLL - přehled fcí - Dependency walker (tool z MS VS .NET).

    V kernel32.dll - je tabulka exportních fcí z ntdll.lib (_imp__***). Native API fce: mají předponu buď Nt, nebo Zw (větš. znamená stejný symbol s oběma prefixy to samé).

    Ntdll - přechod na ring0 - Sysenter/ int 2E - přepne na ring0 a skočí na registry CPU určené místo (určené napevno při bootování) - KiFastCallEntry (switch podle jednotl. fcí - z registrů vybere, kterou má volat, podle Service Descriptor Table (4položky) --> System Service Tables - adresy, počty parametrů, počet fcí).

    Volání fce na ring0 - přes driver & parametr DeviceIoControl nebo napsat si vlastní interrupt & přidat ho do interrupt table (taky přes driver, ale jednoduchý), nebo přidat službu do SDT (v podstatě totéž - "softwarový interrupt") & volat přes Sysenter. Vytvoření fce v C, přidání ring0 prolog, ring0 epilog (aby běžela na ringu 0). Lepší - callgate. Potřebuju zas driver, přístup do Global Descriptor Table - spec. deskriptor pro callgate; stačí ale udělat jednou.

    Driver

    Vytvoření - Windows Driver Development Kit. Fce DriverEntry (pro vytvoření Driver-objectu), DeviceDispatch (pro volání funkcí); DriverEntry Obs. volání IoCreateDevice - vytvoří DriverObject; adresa DeviceDispatch se nastaví v DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL, IRP_MJ_CREATE atd. ]); v DeviceDispatch - switch( MajorFunction ), case IRP_MJ_DEVICE_CONTROL - pro volání pomocí DeviceIoControl. Vrací NTSTATUS ( STATUS_SUCCESS, STATUS_NOT_IMPLEMENTED ). Win DDK - commandline compiler.

    Ovládání: hDevice = CreateFile ( "\\\\.\\DriverName", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) . Volání funkcí - DeviceIoControl( hDevice, dwControlCode, lpInBuf, nInBufSize, lpOutBuf, nOutBufSize, lpRet, lpOverlapped ) - aplikace má 2 buffery, v systému driver pracuje s jedním (kopií prvního, jejíž driverem upravená verze se zkopíruje do druhého). Pro dwControlCode ex. makro CTL_CODE( deviceType, function, method, access ) (ntddk.h).

    Instalace driveru - pomocí .INF souboru ( v DDK - geninf.exe ), nebo pomocí ServiceControlAPI (advapi32.dll) - volání OpenSCManager, CreateService, CloseServiceHandle. Seznam instalovaných driverů - je v Computer Managementu; v DDK pro toto program "drivers.exe", "devicetree.exe"; ve WinDbg (kernel debugger) - příkaz "!drivers".

    Interrupt

    Přechod z ring3 na ring0. Běžně pro interrupt/ system service call/ exceptions (HW/SW) - po vyvolání se octnu v "trap handleru". Exceptions - např. divide error, page fault, overflow, breakpoint, bus error atp. Je to synchronní událost - výsledek provádění akt. operace. Interrupt - SW: instrukce int, HW - asynchronní událost, lze ji maskovat - nastavení IRQ level, uložení stack frame (∀ procesor má nastaven svůj aktuální IRQL, méně důležitá přerušení na něm nepřijímá = jsou maskovaná).

    Několik stupňů důležitosti - Hardware \> software \> passive (IRQL). Deferred Procedure Call/Dispatch - nejdůležitější SW druh. Pokud jádro chce přeplánovat procesy - vyvolá, jinak je standardně voláno pokud vlákno skončí/začne čekat.

    Tabulky deskriptorů - LDT.index, GDT.base, GDT.limit (128) - práva k částem paměti, IDT.base, IDT.limit (256). IDT - interrupt descriptor table - obs. adresy obslužných rutin. Jen tři druhy deskriptorů - TSS Gate (přepnutí procesů), Interrupt gate (maskující přerušení), Trap gate(nemask. přerušení = nemaskovatelné). Všechny drivery používající interrupt: nutné použít ring0 prolog / epilog: alokace místa na zásobníku, příprava trap frame, uložení údajů z thread environment block, registru FS; v epilogu navrácení.

    Callgate

    Aplikace z ring3 může zavolat vlastní fci, která poběží s oprávněním ring0. Spec. deskriptor v GDT - obs. offset (adresu volané fce), selektor ukazující na jiný deskriptor v GDT, s oprávněním segmentu popsaného tímto deskriptorem fce poběží. Při volání callgate se ignoruje offset, použije se jen selektor. Procesor přepne na zásobník ringu 0, uloží na něj stack-size, stack pointer ringu 3, zkopíruje do něj parametry ze zásobníku ringu 3, uloží obs. registrů cs, ip ringu 3 a skočí na adresu uvedenou v callgate.

    Vytvoření callgate: vytvoření driveru - DriverDispatch, komunikace přes DeviceIoControl. Do GDT přidá 2 deskriptory - deskriptor kód. segmentu, do kterého bude ukazovat callgate, deskriptor brány s adresou fce a selektorem předch. kódového segmentu - pomocí fce KeI386AllocateGdtSelectors( SelectorArray, nNumber ). Pro přechody z ring3 na ring0 nutné taky ring0 prolog & epilog stejně jako u interruptu. Návrat z funkce - "far return".

    .NET

    Struktura .NET exáče: "Portable Executable (PE)" - hlavička obs. Common Language Runtime header a metadata, MS intermediate language (MSIL) kód, resource. Odp. přibližně std. EXE. Assembly - balíček kódu - pro distribuci, bezpečnost, instalaci, správu verzí, opakované použití kódu. Oddělení pojmu "aplikace" (log.) od pojmu "soubor" (fyz.) - obs. vše co potřebuje aplikace. Tzv. MSIL assembly - obs. jen kód, satelitní assembly - bez kódu (např. pro lokalizace); default (fallback) assembly - prostředky bez uvedení "culture"(lokalizace). Tj. .NET aplikace může být jediný soubor (assembly) nebo i víc. 1 ze souborů musí obs. manifest (nebo jako zvl. dll) - ten popisuje celou strukturu assembly.

    CLR header - uvádí verzi .NET (1.1/2.0), obs. i digitální podpis celé assembly - "strong name" = hash manifestu & veřejný klíč. Další - MethodDef token (entry point pro exe), atp.

    Metadata - obs. metadata popisující 1 modul, může obs. i manifest - ten popisuje celou assembly (je ale jen v 1 souboru assembly). Manifest :

  • AssemblyDef - jméno, locale (culture), verze (může se nastavit automaticky compilerem), hash algoritmus, veřejný klíč vydavatele.
  • FileDef - seznam všech souborů, jejich hashe, atributy (krom souboru ve kterém je manifest umístěn)
  • ExportedTypesDef - tabulka všech tříd přístupných zvenku & metod (u exe - 1 položka - main() ).
  • ProcessorDef - pro jaké CPU je Assembly určená
  • AssemblyOsDef - typ OS - VER_PLATFORM_WIN32_NT, WIN32_CE (nastavuje se sám při určení typu projektu v devenv).
  • Metadata - Module Metadata Information - ModuleDef, TypeDef, MethodDef, FieldDef, ParamDef, PropertyDef, EventDef (pro všechny entity v modulu). Assembly Reference Metadata Information - infromace o závislostech zvenčí - mohou být vyžadovány další assembly typu dll zvenčí & využívány jejich fce - AssemblyRef (∀ assembly na kterou je odsud odkaz), ModuleRef, TypeRef, MemberRef ( pro úplně vše použité zde).

    Vlastnosti assembly se dají ovlivňovat pomocí překladače (&devenv - vlastnosti projektu), z promptu. C# compiler (csc.exe) defaultně produkuje manifest, pokud je parametr /t:winexe, /t:exe, /t:library, parametrem /t:module jde vytvořit i dll, které se pak pomocí /addmodule: dá použít jako součást jiné assembly (nevytváří se manifest). Přepínač /nostdlib - nepoužijí se std. .NET knihovny. /res: file.res přidá win32 resource, /linkres: file.res - to samé, ale nezabuduje do assembly, jen přidá odkaz. Přepínač /out: - název výstupu. Assembly linker (al.exe) - al.exe /out:soubor.dll /t:dll soubor.mod soubor2.mod. Další přepínače - /embed: file.jpg - přidá lib. soubor do PE s manifestem, /link: - odkaz na samostatný resource, /win32res: přidá soubor typu .RES, /win32icon: přidá ikonu.

    ILDAsm - intermediate language disassembler - ukáže tabulky a metadata v user-friendly podobě, možno procházet i kód v intermediate language. (GUI, souč. .NET SDK). Decompiler do C# - víc, open-source, 3rd party, např. Exemplar. Překládají i mezi C# a VB. Zabránění krádeži kódů - obfuscator - "zatemňovač" kódu - jeden se dá přidat do MSVS, jsou i složité, drahé, profesionální. Hashují identifikátory, přidávají zbytečné fce, skoky a zbytečné instrukce.

    Jednoduchá instalace .NET (marketing) - zkopírování & vytvoření ikon - tj. aplikace == 1 adresář, v něm je všechno. Žádné sdílené dll s různými verzemi atp., každé assembly může používat jen to co má ve své složce, žádné zápisy do registrů ( nastavení si aplikace uchovává přímo v assembly). Uninstall == (ideálně) smazání adresáře. ∀ assembly by cizí využívané assembly měla mít ve své složce ("soukromé"); jde ale umístit i do podadresáře, musí mít uvedeno v konfiguráku ve svém adresáři (XML s příponou .CFG). Assembly mohou být sdílené, jen jsou-li umístěné v Global Assembly Cache (C:\Windows\assembly) (instalátor | al.exe /install:file.dll | gacutil.exe) - tam jsou rozlišené podle strong name - i 2 dll stejného jména s různým strong name jsou v GAC obě. ∀ assembly je zvl. adresář unikátního systémem generovaného jména. Údaje jsou i v registrech (nemazat ručně!).

    ∀ assembly - spousta atributů, jdou nastavit v al.exe / csc.exe: Culture (např. "en-us"), Version ( 2.5.719.2 - assembly version (major & minor), build, revision ), Strong name - spec. typ dig. podpisu pro .NET (dig. podpis je to samé, ale pro jednotlivé lib. soubory). Zajišťuje, že se assembly nerozpadne (hash všech souborů, v manifestu). Generování klíčů - sn.exe.

    Podepisování - signcode.exe, generování certifikátů - makecert.exe / "opravdová" certifikační autorita, .CER -> .SPC (pro signcode) - cert2spc.exe. Ověření údajů - podle strong name, hashe, certifikátu autora, URL odkud assembly pochází (assembly evidence, host evidence).

    Aplication domain - kde běží aplikace. Běžné Win32 - 1 process = 1 aplikace. V .NET pro 1 CLR (1 process) může být n App. Domains, pro každou z nich n assemblies. CLR hlídá izolaci jednotl. domains. IE, ASP.NET - používají jen 1 CLR (a ∀ app./site 1 doménu), shell - 1 CLR ∀ aplikaci. Code Access Security - ∀ aplikace má práva jako "read registry", "read user environment", kontrolována za běhu pomocí Code Acces Security Framework. "Stack Walk" - kontroluje se zda všechny metody na call stacku mají dané právo (a když 1 z nich ne, akce se nepovolí). Bezpečnost na základě rolí - "principal" - informace o identitě přiřazené na zákl. práv pro Windows / .NET passport / jinak, na základě nich povoluje .NET akce (objekt PrincipalPermission, pro role na zákl. práv pro Win - WindowsIdentity, WindowsPrincipal). Impersonate - změna uživatele: Thread.CurrentPrincipal = ... .

    Isolated Storage - i bez práva přístupu k lok. diskům může .NET aplikace uložit omezené množství informací (běžně v Local Settings\Application Data ... pro ∀ strong name aplikace jiné). Objekty IsolatedStorageFilePermission, IsolatedStorage, IsolatedStorageFileStream.

    Skriptování

    Skripty - admin(local/shell) x remote (http). Local - js, vbs, vba (office), msh (microsoft command shell - "nomad" ) - furt beta. Server - dává se přednost C#script, Klient - JScript; v budoucnosti AJAX (Atlas).

    WSF soubor - package víc skriptů (i různé jazyky). Formát xml -

    <package> 
        <job id=" ... " > 
        <script language=" ... " > 
    	.... 
    	text skriptu 
    	.... 
        </script> 
        </job> 
    </package> 
    Spuštění 1 skriptu z balíku - cscript //Job:jobname myscript.wsf. Skript lze i posat v tagu <description>, napsat příklad použití v <example>. Zaregistrovaný ActiveX objekt - <reference progid="Component.class" > - odkaz na něj - lze ho instanciovat a volat metody.

    VBScript

    Interprety skriptů (VBS) - grafický x command-lineový (dá se nastavit defaultní, ten se pustí poklepáním na skript). Ne všechny VBS jsou spustitelné v obou. Window - wcript.exe, command-line: cscript.exe. Ve wscript textové skripty: 1 řádek = 1 message box!.

    Zpráva uživateli - MsgBox( prompt, buttons, titles, helpfile, context ). Buttons - konstanty - buď napsat hodnotu nebo konstantu nadefinovat (interpret by default jména konstant nezná). Dotaz na uživatele - InputBox( prompt, title, default answer, pos-x, pos-y, helpfile, context ).

    Systémové objekty: TextStream (WriteLine, ReadLine) , File, FileSystemObject (pro vytváření souborů - vrací objekty File).

    Pokus o objektové skriptování - objekt WScript. Std objekty, které jsou ve std. interpretu VBS: - WshController -> WshRemote (pro vzdálené spouštění skriptů - nutné přidat práva; v XP už nefunguje), WshNetwork, WshShell, WshArguments. Všechno pod hlavním objektem WScript.

    Wscript.Echo 1, 2, 3 - výpis (odp. MsgBox-u), jméno souboru se skriptem - Wscript.ScriptName , Wscript.Path , Wscript.FullName . Parametry - Wscript.WshArguments , pauza - Wscript.Sleep 10 (ms), Wscript.Quit - konec.

     Set promenna = hodnota  
        Const konstanta = false 
        For i = 1 to 10 
    	... 
        Next 

    WScript.WshShell - objekt ve kterém lze dělat dost věcí: metody .Popup - message box (víc parametrů než Echo), .Run - spuštění cizího programu, .Exec - totéž, ale je objekt, nejen příkaz; můžu se ptát kdy skončil (metoda .Status ); .AppActivate "Název programu" , .SendKeys "..." <- posílá AKTIVNÍMU oknu (když někdo aktivuje jiné, posílá tam); .CreateShortcut , .ExpandEnvironmentSetttings - získá hodnotu environmentové proměnné; .RegRead, .RegWrite, .RegDelete - práce s registry.

    WScript.Network - dotazy na .ComputerName , .UserName , .UserDomain ; .EnumNetworkDrives ; .AddWindowsPrinterConnection , .SetDefaultPrinter .

    WMI - Windows Management Instrumentation = objetky, umožňující pracovat skriptově s driverem (HW, SW) (WMI-compliant). ∀ WMI objekt má vlastnosti (qualifiers), dají se zjistit jejich jména a pracovat s nimi :

     for each Qualifier in Process.Qualifiers 
        Wscript.Echo Qualifier.Name 
    Lze pomocí skriptů, ale i pohodlněji pomocí specializovaných utilit - WMI CIM Studio, WMI Object Browser, VS .NET 2005 Server Explorer. SW - např. vlastnosti procesů, Add/Remove programs. Dá se používat i v .NET - WMI jsou i normální .NET objekty.

    ActiveX - procedura CreateObject vytvoří ActiveX prvek (např. i MSOffice aplikace), ten má svoji vlastní ActiveX hierarchii.

    COM

    Předchůdce .NETu, který je na něm částečně postaven. Původně - DDE (Direct Data Exchange), OLE (Object Linking and Embedding) - např. obrázky ve Wordovských dokumentech. DDE - umožnilo výměnu dat mezi procesy (jen označilo část adres. prostoru za sdílenou (Win16)).

    OLE (OLE 2) - "už není zkratka, ale název :)" - spousta věcí navíc, jeho součástí je COM (Component Object Model). ActiveX je speciální typ COMu (nejznámější). Komunikace mezi procesy uvnitř 1 PC / Microsoft Network, moc to ale nefungovalo (RPC/ odlehčené LRPC, nešlo moc používat); RPC fungovalo až ve vylepšeném Distributed COM. Poslední verze - COM+ - zabudování runtime pro DCOM do jádra (Win2000+).

    COM objekt

    Data a metody, které jsou dělené podle účelu na Interfacy. Interfacy jsou nějaké předdefinované (pro 99.5% účelů) ale jdou definovat vlastní. Definovaných je > 60, často používaných jen pár. Interface IUnknown - povinné pro každý objekt, základ (předek) všech interface, bez něj COM nefunguje.

    GUID - globálně univerzální id (Open Software Foundation). UUID = Universe UID - M$ verze téhož. Podle použití pro třídu - CLSID, pro interface : IID. 128 bit, dělení : DWORD, WORD, WORD, BYTE. Generování CLSID konstant pro nové třídy - GUIDgen.exe (jde i v programu- UuidCreateSequential( UUID * uuid ), UuidCreate( UUID * uuid )). Záruka jednoznačnosti neexistuje, ale možností je tolik, že kolize není pravděpodobná.

    Každý COM objekt je odvozený z rozhraní (větš. předdefinovaných), musí mít metody interfacu IUnknown, ze kterého jsou odvozené ost. interfacy: QueryInterface , AddRef , Release - čítače použití objektu (pokud je == 0, objekt se zničí). Pointer na objekt v COM nemusí být skutečný pointer na objekt, i když ho mám, nemohu volat všechny jeho metody (1 COM objekt může být implementován několika objekty PG jazyka, typicky 1 interface ~ 1 objekt). Typicky můžu volat metody 1 interfacu, pokud chci další, volám QueryInterface( IID_Rozhrani ), dostanu pointer na jeho implementaci. Mohu používat i cizí COM objekty, zabudovat je do svého.

    Každý COM objekt musí mít jeden speciální objekt pro vytváření instancí - Class Factory, aby i cizí procesy mohly bez znalostí parametrů konstruktoru vytvářet mé objekty. Konstruktor Class Factory je vždy bez param. Pro zpřístupnění objektu cizím programům musí být uveden v registrech PC na kterém ho používám. Aby byl objekt v DLL přístupný, musí být exportovaná fce DllGetClassObject(), která vrací pointer na instanci ClassFactory. Exe soubor musí při spuštění registrovat své COM objekty (CoRegisterClassObject() ).

    Vytvoření instance cizího objektu - CoCreateInstance( CLSID, (IUnknown *), TypModulu, IID, &pInterface ), ta volá CoGetClassObject, který potřebuje ClassFactory. Pokud objekt byl vytvořen v jiném programu tak pro předdefinované interfacy umí pro něj systém vytvořit proxy/stub pro přenos volání metod, tj. nemusím se starat, kde objekt je (ale můžu, vynucením parametru u CoCreateInstance). Pro víc instancí mohu sám volat CoGetClassObject a dostanu ClassFactory.

    COM objekty lze tak skládat (agregace), ovládat jimi cizí programy (automation/remotion). Pro std. interfacy je to jednoduché, nestandardní metody - musím se umět zeptat co umí, to je možné přes interface IDispatch. Další způsob zjištění implementovaných věcí - duální rozhraní, napsané staticky (TypeLibrary - .IDL soubor), je možné zjistit vše i bez vytváření instancí (předchůdce manifestu v .NET).

    Drag & Drop

    Zpoč. umělo přenášet jen integer, string atp. COM, .NET umí přenést libovolný COM objekt; na obou stranách se musí implementovat COM interfacy. Zdroj: vytvoření DataObjectu (COM objektu s popisem dat), Cíl: musí implementovat DropTarget (& oznámit systému, které okno bude zachytávat objekty - RegisterDragDrop).

    Když zdroj přijde na to, že uživatel chce udělat D&D, vytvoří nový objekt, zavolá DoDragDrop, potom myš & klávesnice patří JEN této funkci. Když fce zjistí že myš je nad oknem, které má implementovaný D&D, zavolá DragEnter - ten se může zeptat, jakého typu je cíl & podle toho vrátit, co by se stalo, kdyby tam objekt spadnul. Zdroj - udává typ kurzoru, jaký se zobrazuje (GiveFeedback()). Pokrač. - DragOver, DragLeave - návr. hodnoty bývají stejné jako DragEnter. Přerušení DragDrop - změna stavu klávesnice & myši - Win se zeptá ZDROJE, co se má udělat (QueryContineDialog()) - OK/DROP/CANCEL.

    V cíl. okně může Drop data převzít & pracovat s nimi, nebo si zapamatovat kopii celého COM objektu (i když s ním nic neumí).

    IRootStorage, IPersistentStorage

    Když chci ukládat COM objekty na disk, musí implementovat interface IPersistentStorage. Při D&D klient získal ukazatel na DataObject, zjistí jestli má IPeristentStorage; pokud ne - Error!, tj. objekt prostě nejde uložit (nejlepší ani nepovolit drop).

    Když budu chtít mít dokument, kam budu cpát objekty - CoCreateDocFile(), dostanu dokument, který implementuje IRootStorage (sice jsem ho nenapsal, ale je "můj"), to je vlastně root filesystému v 1 souboru. V něm se dá volat CreateStorage() -adresář, CreateStream() - soubor, Write(). Uložení cizího objektu - přes metodu InitNew() interfacu IPersistentStorage, dám cizímu programu adresář v mém dokumentu pro cizí objekt, ten si ho tam "nějak" uloží. Když na PersistentStorage zavolám Save(), Commit(), to uloží cizí objekt, vrátí mi všechny pointery (Release()), pak můžu soubor zkopírovat, otevřít, hledat v něm podadresáře atd. RootStorage->Release() - zavření souboru.

    V .NET - komunikace chytřejší - manifesty, ale jinak podobné