Delphi Kompendium Roz12

background image

Logowanie | Rejestracja | Forum | Pomoc | Reklama | Szukaj

Strona główna :: Delphi :: Kompendium

Edytuj

Historia

Rozdział 12

WinAPI

Nie sposób było nie wspomnieć w tej książce o WinAPI. Z tym terminem zetknąłeś się już wielokrotnie podczas
lektury niniejszej publikacji. Teraz chciałbym omówić ten temat nieco dogłębniej. Nie jest możliwe bowiem
zawarcie wszystkich informacji dotyczących WinAPI w jednym rozdziale ? temat ten jest na tyle rozległy, że
można by mu poświęcić osobną książkę. Więcej o WinAPI możesz dowiedzieć się ze strony

http://msdn.microsoft.com

lub z systemu pomocy Delphi (znajdziesz tam dokładny opis funkcji i procedur).

Spis treści

1 Czym tak naprawdę jest WinAPI?

1.1 Zasady tworzenia programów za pomocą WinAPI

1.2 Brak zdarzeń

1.3 Brak komponentów

1.4 Zalety wykorzystania WinAPI

2 Pierwszy program

3 Funkcja okienkowa

4 Rejestracja klasy

5 Tworzenie formularza

6 Komunikaty i uchwyty

7 Łańcuchy

7.1 Konwersja łańcuchów

7.2 Funkcje operujące na łańcuchach

7.2.1 CharLower, CharUpper

7.2.2 lstrlen

7.2.3 lstrcpyn

8 Tworzenie kontrolek

8.1 Umieszczanie kontrolek przy starcie programu

8.2 Flagi kontrolek

9 Obsługa zdarzeń

10 Uchwyty do kontrolek

11 Tworzenie bardziej zaawansowanych kontrolek

11.1 Pozostałe kontrolki

12 Wyświetlanie grafiki

12.1 Rysowanie w WinAPI

12.2 Kontekst urządzenia graficznego

12.3 Obsługa WM_PAINT

12.3.1 Zmiana koloru tła

12.4 Ładowanie i wyświetlanie bitmapy

13 Ładowanie zasobów

13.1 Skompilowane zasoby

13.2 Wykorzystanie zasobów

13.2.1 Wyświetlenie formularza

13.2.2 Ustawianie wartości komponentów formularza

13.3 LockResource, LoadResource, FindResource

13.4 Zapisywanie plików na dysku

14 Podsumowanie

Można powiedzieć, że ten rozdział przeznaczony jest dla ?maniaków? Delphi w pozytywnym tego słowa
znaczeniu. Programowanie w WinAPI nie jest bowiem łatwe i wygodne, ale umożliwia zachowanie większej
kontroli nad programem.

Czym tak naprawdę jest WinAPI?

Pełna nazwa tego skrótu to Windows Application Programming Interface . Dla osób, które wcześniej tworzyły
swoje programy w Turbo Pascalu, biblioteka wizualna i klasy mogą wydać się dość niezrozumiałe. Z kolei dla
niektórych prostsze może okazać się rozpoczęcie pisania programów metodą API. Ty jednak jesteś już zapewne
przyzwyczajony do stosowania klas i komponentów, a WinAPI może Ci się wydać trudne lub po prostu
nieciekawe. Problem, którego rozwiązanie przy użyciu komponentów wymagało jednego wiersza kodu, przy
wykorzystaniu WinAPI może oznaczać konieczność napisania nawet kilkudziesięciu wierszy! Dlatego nie
zdziwię się, jeżeli ominiesz ten rozdział i przejdziesz od razu do kolejnego.

Zasady tworzenia programów za pomocą WinAPI

Wyobraź sobie pisanie programów bez wykorzystania formularzy, komponentów i wszystkich innych
udogodnień oferowanych przez Delphi. Nasze programy będą oparte jedynie na podstawowych modułach
Windows.pas i Messages.pas. Wszystkie funkcje, z których będziemy korzystać, zawarte są w bibliotekach DLL
systemu Windows. Ich załadowanie do programu odbywa się w module Windows.pas.

Nam, użytkownikom tych bibliotek, potrzebna jest wiedza o ich budowie ? liczbie i typie parametrów,
wartościach zwracanych przez funkcję itp. Stąd miej na uwadze perspektywę częstego zaglądania do pomocy
Delphi.
Przy tej okazji warto wspomnieć o możliwości choć częściowego nauczenia się języka C. System Windows był
pisany w tym języku, stąd opisy wszystkich funkcji API (deklaracje) są również w nim przedstawione. Jest to
pewna okazja do poznania choćby w małym stopniu budowy języka C.

Gdy kiedyś zaczniesz pisać programy w języku C++, znajomość WinAPI bardzo Ci się przyda! Nazwy funkcji są
takie same ? jedynie składnia nieco się różni.

Brak zdarzeń

Delphi

Artykuły
Kompendium
Gotowce
FAQ
.NET

Turbo Pascal

FAQ

PHP

FAQ

Java

FAQ

C/C++

Artykuły
FAQ

C#

Wprowadzenie

Assembler

FAQ

(X)HTML
CSS
JavaScript
Z pogranicza
Algorytmy

WIĘCEJ

»

Delphi
C/C++
Turbo Pascal
Assembler
PHP

Programy
Dokumentacja
Kursy
Komponenty

WIĘCEJ

»

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

1 z 18

2009-03-14 15:43

background image

Podczas pisania programów w ?czystym? API będziemy pozbawieni wygodnego mechanizmu, jakim są
zdarzenia. Jak pamiętasz z rozdziału 5., mechanizm zdarzeń można zastąpić poprzez komunikaty Windows.
Ten moment jest więc dobrą okazją, aby cofnąć się do rozdziału 5. i przypomnieć sobie zasadę funkcjonowania
komunikatów.

Brak komponentów

W API będziemy musieli obyć się bez komponentów. Te ?klocki?, jakimi są komponenty, w dużym stopniu
odciążały nas od mozolnego operowania komunikatami czy pamięcią. Nie będziemy jednak pozbawieni
typowych kontrolek Windows, jak przycisk czy lista rozwijalna ? będziemy je tworzyć w kodzie programu za
pomocą funkcji CreateWindow.

Zalety wykorzystania WinAPI

Zastanawiasz się może, co takiego zyskasz, używając mechanizmów WinAPI? Powiem szczerze: niewiele.
Dużym plusem jest szybkość działania aplikacji oraz rozmiar. Programy tworzone w Delphi i wykorzystujące
VCL mają duże rozmiary. Nawet prosty program w postaci ?czystego? formularza potrafi zajmować grubo
ponad 300 kB. Aplikacje wykorzystujące jedynie WinAPI mogą zajmować nawet 16 kB i są wykonywane
znacznie szybciej. Różnica jest znaczna, nieprawdaż?

Czytając ten rozdział, masz możliwość zaznajomienia się z dotąd nieznanymi funkcjami, z których być może
będziesz musiał skorzystać w swoich programach, gdy VCL okaże się niewystarczający i zbytnio będzie Cię
ograniczał.

Głównymi zaletami Delphi są przecież biblioteka VCL, klasy oraz formularze, dzięki którym tworzenie
programów trwa znacznie krócej. Jeśli porzucisz te udogodnienia, pisanie aplikacji może zająć więcej czasu, a
nie po to chyba tworzono Delphi, prawda?

Podsumowując: WinAPI jest okazją do głębszego zaznajomienia się z tematyką programowania w systemie
Windows, lecz nie nadaje się do pisania dużych projektów.

Pierwszy program

Przypomnij sobie rozdział 2. Wówczas poznawałeś dopiero język Object Pascal, ale tworzone przez Ciebie
programy także nie zawierały żadnych komponentów czy formularzy. Te programy po skompilowaniu także
miały rozmiar kilkunastu kilobajtów ? można zatem powiedzieć, że już wtedy pisałeś programy WinAPI!
Zamknij formularz i Edytor kodu. Następnie z menu Project wybierz polecenie View Source. Kod źródłowy
projektu (pliku *.dpr) doprowadź do takiej postaci:

program Project1;

uses
Windows;

begin

end.

Na razie nie potrzebujemy pliku zasobów, więc usunąłem także dyrektywę {$R}. Ikonę naszego programu
możemy dodać w następnej kolejności. Tak powstały kod źródłowy zapisz gdzieś na dysku. Następnie z menu
Project wybierz polecenie Build, co spowoduje skompilowanie aplikacji i utworzenie pliku *.exe. Spójrz teraz na
rozmiar aplikacji ? u mnie jest to 14 kB! Na razie co prawda program jest ?pusty?, ale już wkrótce co nieco do
niego dodamy.

Funkcja okienkowa

Dotąd nasz program kończył pracę zaraz po uruchomieniu go ? w bloku begin nie ma przecież żadnej
instrukcji. Naszym celem jest napisanie takiego programu w WinAPI, który zakończyłby pracę po interwencji
użytkownika ? zamknięciu okna. Musimy więc napisać kod, który spowodowałby wyświetlenie formularza.
Jednym z etapów tworzenia takiego formularza jest napisanie funkcji okienkowej. Funkcja taka będzie
odpowiedzialna za odbieranie wszystkich komunikatów, które docierają do okna i ewentualną reakcję na dany
komunikat. Zadeklaruj więc w programie taką funkcję:

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

begin
end
;

Znaczenie parametrów tej funkcji jest następujące:

Wnd ? uchwyt do okna.
uMsg ? komunikat.
wPar ? pierwsza wartość komunikatu.
lPar ? druga wartość komunikatu.

Taka budowa jest nieprzypadkowa ? aby cały program został prawidłowo skompilowany, funkcja okienkowa
musi wyglądać tak, jak to przedstawiłem powyżej. Pierwszym komunikatem, jaki będzie obsługiwany przez
funkcję okienkową, jest WM_DESTROY. Program musi odpowiednio zareagować na próbę zamknięcia programu.

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

begin
{ na początek zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

{ w tym miejscu należy obsłużyć należne komunikaty }
{ w funkcji DefWindowProc przekazujemy takie same parametry, jak w funkcji okienkowej }
WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

Jak widzisz, instrukcja case sprawdza, jaki komunikat został odebrany przez funkcję okienkową. W przypadku
odebrania komunikatu WM_DESTROY program kończy pracę ? PostQuitMessage. Na samym jednak początku
przypisujemy funkcji wartość zwrotną ? cyfrę 0. W przeciwnym wypadku ? jeżeli nadesłany komunikat ?nas
interesuje? ? przekazujemy go dalej, do domyślnego okna. Realizuje to funkcja DefWindowProc; parametry
muszą być identyczne z parametrami funkcji okienkowej.

RSS | Forum | Pastebin |

Regulamin | Pomoc | Usuń

cookies | Prawa autorskie |

Kontakt | Reklama

Copyright © 2000-2006 by Coyote Group 0.9.3-pre3

Czas generowania strony: 1.6790 sek. (zapytań SQL:

12)

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

2 z 18

2009-03-14 15:43

background image

Aby program został prawidłowo skompilowany, na liście uses musi znaleźć się moduł Messages.pas.

Rejestracja klasy

Aby cały formularz mógł zostać stworzony, uprzednio należy zarejestrować klasę. Rejestracja klasy następuje
poprzez wywołanie funkcji RegisterClass z modułu Windows.pas.

function RegisterClass

(

const lpWndClass: TWndClass

)

: ATOM;

stdcall;

W parametrze owej funkcji należy podać zmienną wskazującą rekord TWndClass:

TWndClass =

packed record

style: UINT;
lpfnWndProc: TFNWndProc;
cbClsExtra:

Integer

;

cbWndExtra:

Integer

;

hInstance: HINST;
hIcon: HICON;
hCursor: HCURSOR;
hbrBackground: HBRUSH;
lpszMenuName:

PAnsiChar

;

lpszClassName:

PAnsiChar

;

end;

Powyższy rekord określa wygląd formularza, kolor tła, styl i kursor. Znacznie parametrów jest następujące:

style ? parametr ów określa styl wyświetlanego okna. Możliwe jest mieszanie stylów za pomocą
operatora or.
lpfnWndProc ? jest to wskazanie na funkcję okienkową.
cbClsExtra ? liczba dodatkowych bajtów alokowanych wraz z rekordem.
cbWndExtra ? liczba dodatkowych bajtów alokowanych wraz z instancją okna.
hInstance ? uchwyt do zasobów.
hIcon ? identyfikacja formularza.
hCursor ? kursor używany w czasie wyświetlania formularza.
hbrBackground ? tło formularza. Możliwe jest zastosowanie jednej z poniższych wartości:
COLOR_ACTIVEBORDER, COLOR_ACTIVECAPTION, COLOR_APPWORKSPACE, COLOR_BACKGROUND,
COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNTEXT, COLOR_CAPTIONTEXT, COLOR_GRAYTEXT,
COLOR_HIGHLIGHT, COLOR_HIGHLIGHTTEXT, COLOR_INACTIVEBORDER, COLOR_INACTIVECAPTION,
COLOR_MENU, COLOR_MENUTEXT, COLOR_SCROLLBAR, COLOR_WINDOW, COLOR_WINDOWFRAME,
COLOR_WINDOWTEXT.
lpszMenuName ? wskazanie na łańcuch określający menu używane w programie.
lpszClassName ? wskazanie na nazwę klasy (wartość typu PChar).

Rejestracja nowej klasy może być wykonana w poniższy sposób:

var
Wnd: TWndClass; // klasa okna

begin

with Wnd do

begin

lpfnWndProc := @WndProc; // funkcja okienkowa
hInstance := hInstance; // uchwyt do zasobów
lpszClassName :=

'My1stApp'

; // klasa

hbrBackground := COLOR_WINDOW; // kolor tła

end;

RegisterClass

(

Wnd

)

; // zarejestruj nową klasę

end;

W moim przypadku nie było konieczne wypełnianie wszystkich pól rekordu TWndClass. Przypisałem jedynie te
pola, które wydawały się konieczne do uzyskania przynajmniej podstawowego wyglądu formularza.

Tworzenie formularza

Na szczęście tworzenie samego formularza nie jest czynnością zbytnio skomplikowaną. Realizuje to bowiem
jedna instrukcja ? CreateWindow:

function CreateWindow

(

lpClassName:

PChar

; lpWindowName:

PChar

;

dwStyle: DWORD; X, Y, nWidth, nHeight:

Integer

; hWndParent: HWND;

hMenu: HMENU; hInstance: HINST; lpParam:

Pointer

)

: HWND;

Przyznasz, że ilość parametrów jest spora:

lpClassName ? nazwa klasy (wartość PChar). Wartość ta musi się równać wartości wpisanej w rekordzie
TWndClass.
lpWindowName ? łańcuch określający tekst, który będzie wyświetlany na formularzu. Znaczenie
parametru można porównywać do właściwości Caption komponentów.
dwStyle ? styl okna (tabela 12.1).
x ? położenie formularza w poziomie. Wstawienie w to miejsce stałej CW_USEDEFAULT powoduje
automatyczne dopasowanie położenia przez system (nowe okno będzie przesunięte lekko w lewą stronę).
y ? położenie formularza w pionie. Wstawienie w to miejsce stałej CW_USEDEFAULT powoduje
automatyczne dopasowanie położenia przez system.
nWidth ? szerokość formularza. Tutaj także stała CW_USEDEFAULT powoduje automatyczne
dopasowanie szerokości.
nHeight ? wysokość formularza. Stała CW_USEDEFAULT powoduje dopasowanie wysokości formularza.
hWndParent ? uchwyt do okna rodzica.
hMenu ? wskazanie do menu, które ma być użyte w programie.
hInstance ? określa instancję modułu, który ma być kojarzony z programem.

Na podstawie tych danych utworzenie formularza może wyglądać tak:

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

3 z 18

2009-03-14 15:43

background image

CreateWindow

(

'My1stApp'

,

'Pierwszy program w WinAPI'

,

WS_VISIBLE

or WS_TILEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

0

,

0

, hInstance,

NIL

)

;

Tabela 12.1. Najczęstsze wartości określające styl okna

Wartość

Opis

WS_OVERLAPPED

Okno posiada pasek tytułowy oraz obramowanie

WS_CHILD

Potomne okno, które nie może ?wyjść? poza okno rodzicielskie

WS_POPUP

Okno dialogowe

WS_CAPTION

Okno ma pasek tytułu

WS_SYSMENU

Okno ma menu systemowe

WS_MINIMIZEBOX

Okno ma przycisk minimalizacji

WS_MAXIMIZEBOX

Okno ma przycisk maksymalizacji

WS_VISIBLE

Okno jest widoczne

WS_HIDE

Okno jest ukryte

WS_DISABLED

Nieaktywne okno ? nie reaguje na zdarzenia

WS_BORDER

Okno posiada ramkę

Listing 12.1. Pierwszy program napisany w WinAPI

{
Copyright (c) 2002 by Adam Boduch
}

program WndApp;

uses
Windows,
Messages;

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

begin
{ na początek zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

{ w tym miejscu należy obsłużyć należne komunikaty }
{ w funkcji DefWindowProc przekazujemy takie same parametry, jak w funkcji okienkowej }
WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

var
Wnd: TWndClass; // klasa okna
Msg: TMsg;

begin

with Wnd do

begin

lpfnWndProc := @WndProc; // funkcja okienkowa
hInstance := hInstance; // uchwyt do zasobów
lpszClassName :=

'My1stApp'

; // klasa

hbrBackground := COLOR_WINDOW; // kolor tła

end;

RegisterClass

(

Wnd

)

; // zarejestruj nową klasę

CreateWindow

(

'My1stApp'

,

'Pierwszy program w WinAPI'

,

WS_VISIBLE

or WS_TILEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

0

,

0

, hInstance,

NIL

)

;

while GetMessage

(

msg,

0

,

0

,

0

)

do DispatchMessage

(

msg

)

;

end.

W listingu 12.1 zaprezentowano cały kod źródłowy programu. Nie omawiałem jeszcze ostatnich instrukcji tego
listingu. Są one bardzo ważne ? bez nich program nie będzie mógł zostać uruchomiony. Operacje te muszą być
wykonane, aby funkcja okienkowa otrzymała potrzebne meldunki. Podczas uruchamiania program musi wejść w
tzw. fazę meldunków. Funkcja GetMessage pobiera kolejno meldunki, wpisując je do struktury TMsg (parametry
są nieistotne), a następnie przekazuje funkcji DispatchMessage, która z kolei przekazuje meldunek funkcji
okienkowej.

Komunikaty i uchwyty

Pisząc programy w WinAPI, będziemy posługiwali się wyłącznie komunikatami jako formą zastępującą zdarzenia
(funkcje SendMessage i PostMessage). Warto więc przypomnieć sobie informacje na temat wysyłania
komunikatów. Ich odbieranie będzie następowało tylko w funkcji okienkowej.
Odświeżmy zatem pamięć ? komunikaty można podzielić na następujące kategorie:

komunikaty klawiaturowe (użytkownik nacisnął lub zwolnił jakiś klawisz),
komunikaty myszy (użytkownik wykonał jakąś czynność myszą),
komunikaty zegara, oznaczające upływ określonego odcinka czasu,
komunikaty systemu ? tworzenie okna, zmiana jego rozmiaru i położenia, zwijanie i rozwijanie okna,
zmiana kolorów systemowych itp.,
komunikaty wewnętrzne ? wysyłane przez inne okna utworzone w naszym programie.

W każdym komunikacie należy podać uchwyt okna docelowego (lub kontrolki docelowej). Uchwyt jest liczbą
32-bitową, która identyfikuje kontrolkę w systemie Windows. To właśnie Windows przydziela uchwyty różnym
kontrolkom. Nazwa typu reprezentującego uchwyt zaczyna się od litery H, czyli np. HWND, HBRUSH, HFONT czy

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

4 z 18

2009-03-14 15:43

background image

HBITMAP

. Dzięki temu łatwo jest rozpoznać, czy dana zmienna jest uchwytem.

Łańcuchy

Podczas pisania programów w WinAPI będziemy używali jedynie łańcuchów typu PChar lub łańcuchów w formie
tablicy. Stosowanie typu String powoduje spowolnienie działania programu i zużywanie większej ilości pamięci.

Typ PChar ma jeszcze jedną zaletę ? można dokonywać na nim takich operacji:

P2 :=

'To jest Delphi'

;

P1 := P2 +

8

;

Pozornie wygląda to tak, jakby do zmiennej P2 dodawana była cyfra 8. W rzeczywistości do typu P1
przypisujemy wartość zmiennej P2, tyle że bez pierwszych 8 znaków. Podczas lektury dalszej części książki
możesz spotkać się także z deklaracjami zmiennych w postaci tablicy:

Variable :

array

[

0

..

255

]

of

char

;

Do takiej zmiennej można następnie przypisać dane w zwykły sposób, tyle że ich wielkość będzie ograniczona
do 255 znaków.

Variable :=

'Adam Boduch'

;

Konwersja łańcuchów

W VCL ten problem nie istniał ? moduł SysUtils posiadał odpowiednie funkcje, umożliwiające konwersję typów.
Pisząc programy API, nie będziemy mogli z nich skorzystać ? pozostaje nam użycie funkcji zastępczych, np.
wvsprintf

.

Oto możliwy sposób wykonania funkcji zastępczej:

function

IntToStr

(

Value :

Integer

)

:

String

;

var
Buffer :

array

[

0

..

255

]

of

char

; // bufor, w którym przechowywać będziemy dane

begin
wvsprintf

(

Buffer,

'%d'

, @Value

)

; // tu następuje funkcja konwersji

Result

:= Buffer; // zwracamy rezultat

end;

Funkcja wvsprintf służy do konwertowania tekstu. Pierwszym parametrem musi być wskazanie zwracanego
przez funkcję ciągu. Ja zadeklarowałem Buffer ? 256-elementową tablicę typu Char. Drugi parametr to tzw.
maska. Jeśli wstawimy w to miejsce znak %d, zostanie on zastąpiony liczbą typu Integer. Owa liczba to
zmienna Value, przekazywana jako trzeci parametr. Przykładowy program prezentujący działanie łańcuchów,
zamieściłem w listingu 12.2.

W powyższej funkcji IntToStr zadeklarowałem tablicę 256-elementową (standardowo),
chociaż tak naprawdę aż tak duża wartość nie jest konieczna.

Wyjątkowo w powyższej funkcji jako zwracanego rezultatu użyłem typu String. Zrobiłem to
tylko po to, aby upodobnić budowę funkcji do rzeczywistego wyglądu funkcji IntToStr z
modułu SysUtils.

Listing 12.2. Pełny kod źródłowy programu

{
Copyright (c) 2002 by Adam Boduch
}

uses Windows;

function

IntToStr

(

Value :

Integer

)

:

String

;

var
Buffer :

array

[

0

..

255

]

of

char

; // bufor, w którym przechowywać będziemy dane

begin
wvsprintf

(

Buffer,

'%d'

, @Value

)

; // tu następuje funkcja konwersji

Result

:= Buffer; // zwracamy rezultat

end;

begin
MessageBox

(

0

,

PChar

(

'Witaj w '

+

IntToStr

(

12

)

+

' części książki!'

)

,

'Witaj!'

, MB_OK

)

; //

wyświetl wartość zmiennej
end.

Inny przykład wykorzystania funkcji wvsprintf:

Buffer :

array

[

0

..

255

]

of

char

;

Format

:

packed record // deklaracja rekordu danych do konwersji

Int

:

Integer

;

Fl :

String

;

end;

begin
{ wypełnienie danych do konwersji }

Format

.

Int

:=

11

;

Format

.

Fl

:=

'Adam Boduch'

;

wvsprintf

(

Buffer,

'Witaj w %d części kursu, ja nazywam się %s!'

, @

Format

)

;

MessageBox

(

0

, Buffer,

''

,

0

)

;

end.

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

5 z 18

2009-03-14 15:43

background image

W tym wypadku w drugim parametrze w łańcuchu znajdują się dwa znaki ? %s i %d. Zostaną one po konwersji
zastąpione danymi w postaci liczby Integer oraz łańcucha String.

Funkcje operujące na łańcuchach

Poniżej przedstawiam kilka funkcji WinAPI operujących na łańcuchach. Mogą one okazać się przydatne podczas
pisania aplikacji w API.

CharLower, CharUpper

function CharLower

(

lpsz:

PChar

)

:

PChar

;

stdcall;

function CharUpper

(

lpsz:

PChar

)

:

PChar

;

stdcall;

Obie funkcje powodują zamianę znaków odpowiednio na małe lub wielkie litery. Pierwsza z nich (CharLower)
zamienia litery z wielkich na małe, a CharUpper ? z małych na wielkie.

program main;

uses Windows;

begin
MessageBox

(

0

, CharLower

(

'TO JEST PROGRAM W WINAPI'

)

,

''

, MB_OK

)

;

MessageBox

(

0

, CharUpper

(

'to jest program w winapi'

)

,

''

, MB_OK

)

;

end.

Warto się zainteresować także funkcją CharLowerBuff i CharUpperBuff. Obie także powodują zamianę znaków,
lecz posiadają także dodatkowy parametr, który określa liczbę znaków, które mają zostać zamienione.

lstrlen

function lstrlen

(

lpString:

PChar

)

:

Integer

;

stdcall;

Funkcja lstrlen podaje długość łańcucha określonego w parametrze lpString. Długość podawana jest w
znakach.

Writeln

(

lstrlen

(

'Adam'

))

;

Powyższa instrukcja wyświetli na ekranie liczbę 4.

lstrcpyn

function lstrcpyn

(

lpString1, lpString2:

PChar

; iMaxLength:

Integer

)

:

PChar

;

stdcall;

Funkcja służy do kopiowania części łańcucha do drugiej zmiennej. Pierwszy parametr musi być wskazaniem
łańcucha, do którego zostaną skopiowane dane. Drugi parametr ? lpString2 ? to miejsce, z którego dane
zostaną pobrane. Ostatni parametr ? iMaxLength ? określa liczbę znaków do skopiowania:

program main;

uses Windows;

{$APPTYPE CONSOLE}

var
P1 :

array

[

0

..

50

]

of

char

;

begin
lstrcpyn

(

P1,

'Delphi jest narzędziem typu RAD'

,

7

)

;

Writeln

(

P1

)

;

Readln

;

end.

Powyższy kod źródłowy spowoduje wyświetlenie na ekranie napisu Delphi.

Tworzenie kontrolek

Zarówno tworzenie komponentów, jak i różnych kontrolek odbywa się za pośrednictwem funkcji CreateWindow.
W przypadku komponentów nie będzie konieczna rejestracja nowych klas itp. elementów. Do stworzenia
nowego komponentu wystarczy napisanie jednego wiersza kodu. Komponent należy utworzyć z flagą WS_CHILD
oraz WS_VISIBLE. Stworzenie przycisku będzie więc wyglądało następująco:

CreateWindow

(

'BUTTON'

,

'Przycisk'

, WS_CHILD

or WS_VISIBLE,

100

,

100

,

120

,

25

, Wnd,

0

,

hInstance,

nil

)

;

Jedyną charakterystyczną cechą jest pierwszy parametr tej funkcji. Jeżeli chcesz stworzyć przycisk, musisz w to
miejsce wpisać słowo BUTTON. Drugi parametr to tekst, który będzie widniał na przycisku. Trzeci parametr to
flagi komponentu. Dalsza część jest już taka sama, jak w przypadku tworzenia formularza. W tabeli 12.2
umieściłem wartości, jakie może przyjmować pierwszy parametr funkcji CreateWindow.

Tabela 12.2. Możliwe wartości pierwszego parametru funkcji CreateWindow

Wartość

Opis

BUTTON

Przycisk ? odpowiednik komponentu TButton

COMBOBOX

Lista rozwijalna ? odpowiednik TComboBox

EDIT

Kontrolka edycyjna ? jedno liniowa. Odpowiednik komponentu TEdit

LISTBOX

Kontrolka wielowierszowa. Odpowiednik TListBox

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

6 z 18

2009-03-14 15:43

background image

MDICLIENT

Okno potomne ? MDI

SCROLLBAR

Pasek przewijania ? inaczej TScrollBar

STATIC

Etykieta tekstowa. Odpowiednik TLabel

Taka kontrolka będzie więc ?dzieckiem? w stosunku do formularza (WS_CHILD) i będzie także widoczna
(WS_VISIBLE).

Jeżeli chcesz, aby kontrolka na starcie była niewidoczna, użyj flagi WS_HIDE.

Pamiętaj, aby podczas tworzenia nowej kontrolki w parametrze hWndParent (czwarty od końca) podać uchwyt
okna głównego. Parametr ów określa uchwyt okna ?rodzica? ? w tym wypadku formularza.

Umieszczanie kontrolek przy starcie programu

Jeżeli chcemy, aby kontrolki były tworzone na starcie programu, kod należy umieścić w funkcji okienkowej.
Konieczne jest także obsłużenie komunikatu WM_CREATE. Oto kod:

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

begin
{ na początek zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

WM_CREATE:
CreateWindow

(

'BUTTON'

,

'Przycisk'

, WS_CHILD

or WS_VISIBLE,

100

,

100

,

120

,

25

, Wnd,

0

,

hInstance,

nil

)

;

WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

W przypadku zastosowania takiej funkcji okienkowej, jaką przedstawiono powyżej, na formularzu w punkcie
100,100 zostanie umieszczony przycisk. W listingu 12.3 znajduje się kod źródłowy programu, którego efektem
jest umieszczenie 5 przycisków na raz.

Listing 12.3. Umieszczanie kilku przycisków

{
Copyright (c) 2002 by Adam Boduch
}

program ChildApp;

uses
Windows,
Messages;

function

IntToStr

(

Value :

Integer

)

:

String

;

var
Buffer :

array

[

0

..

255

]

of

char

; // bufor, w którym przechowywać będziemy dane

begin
wvsprintf

(

Buffer,

'%d'

, @Value

)

; // tu następuje funkcja konwersji

Result

:= Buffer; // zwracamy rezultat

end;

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

var
i :

Integer

;

begin
{ na początek zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

WM_CREATE:

begin

for I :=

1

to

5

do

CreateWindow

(

'BUTTON'

,

PCHar

(

'Przycisk nr: '

+

IntToStr

(

i

))

, WS_CHILD

or WS_VISIBLE,

100

,

100

+ i *

30

,

120

,

25

, Wnd,

0

, hInstance,

nil

)

;

end;

WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

var
Wnd: TWndClass; // klasa okna
Msg: TMsg;

begin

with Wnd do

begin

lpfnWndProc := @WndProc; // funkcja okienkowa
hInstance := hInstance;
lpszClassName :=

'My1stApp'

; // klasa

hbrBackground := COLOR_WINDOW; // kolor tła

end;

RegisterClass

(

Wnd

)

; // zarejestruj nową klasę

CreateWindow

(

'My1stApp'

,

'Pierwszy program w WinAPI'

,

WS_VISIBLE

or WS_TILEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

0

,

0

, hInstance,

NIL

)

;

while GetMessage

(

msg,

0

,

0

,

0

)

do DispatchMessage

(

msg

)

;

end.

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

7 z 18

2009-03-14 15:43

background image

W kodzie wykorzystaliśmy wcześniej napisaną funkcję IntToStr. Umieszczenie 5 kontrolek następuje w pętli,
dlatego też za każdą iteracją należy zmieniać położenie przycisku w pionie, wykonując takie działanie:

100 + I * 30;

Powoduje to dodanie do liczby 100 wartości z mnożenia ? np. 30, 60, 90 itd. Działanie programu prezentuje
rysunek 12.1.

Rysunek 12.1. Działanie programu

Flagi kontrolek

Poszczególne kontrolki umieszczone na formularzu mogą posiadać dodatkowe flagi, określające zachowanie lub
wygląd komponentu. Owe flagi można podawać jako trzeci parametr polecenia CreateWindow, łącząc je
operatorem or. W tabelach 12.3 ? 12.6 przedstawiam najczęściej używane flagi.

Tabela 12.3. Flagi używane z kontrolką BUTTON

Flaga

Krótki opis

BS_3STATE

Kontrolka (przycisk) stanie się komponentem ? la TCheckBox

BS_AUTO3STATE

Flaga podobna do BS_3STATE, tyle że komponent może przybierać wartość
?zaznaczony?

BS_AUTORADIOBUTTON

Kontrolka (przycisk) stanie się komponentem ? la TRadioButton (rysunek 12.2)

BS_DEFPUSHBUTTON

Powoduje, że przycisk zostanie wyświetlony z czarną, pogrubioną obwódką

BS_GROUPBOX

Komponent zostanie wyświetlony z obwódką (rysunek 12.3)

BS_BITMAP

Umożliwia wyświetlanie bitmapy na kontrolce

BS_BOTTOM

Ustawia tekst na samym dole komponentu

BS_CENTER

Centruje tekst w poziomie

BS_ICON

Umożliwia wyświetlanie ikony na komponencie

BS_LEFT

Tekst będzie wyrównany do lewej strony

BS_MULTILINE

Flaga umożliwia wyświetlanie kilku wierszy tekstu

BS_RIGHT

Tekst będzie wyrównany do prawej strony

BS_TOP

Tekst zostanie umieszczony u góry kontrolki

BS_VCENTER

Tekst zostanie wyśrodkowany w pionie

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

8 z 18

2009-03-14 15:43

background image

Rysunek 12.2. Przyciski w formie komponentu TRadioButton

Rysunek 12.3. Przyciski w formie kontrolek TGroupBox

Tabela 12.4. Flagi używane z kontrolką COMBOBOX

Flaga

Krótki opis

CBS_DISABLENOSCROLL

Pasek przewijania zostanie zablokowany

CBS_DROPDOWN

Lista rozwijalna zostanie aktywna

CBS_DROPDOWNLIST

Nie będzie możliwe edytowanie listy rozwijalnej (zaznaczona pozycja nie będzie
mogła być zmieniana)

CBS_LOWERCASE

Konwertuje tekst wpisany w kontrolce na małe litery

CBS_UPPERCASE

Konwertuje tekst wpisany w kontrolce na wielkie litery

CBS_SORT

Automatyczne sortowanie danych wpisanych w kontrolce

Tabela 12.5. Flagi używane z kontrolką EDIT

Flaga

Krótki opis

ES_AUTOHSCROLL

Automatycznie przewiń tekst w kontrolce w poziomie, jeżeli użytkownik wpisał więcej
znaków niż może być w niej wyświetlone

ES_CENTER

Wyśrodkuj tekst, jeżeli kontrolka zawiera wiele wierszy

ES_LEFT

Wyrównaj tekst do lewej strony

ES_LOWERCASE

Konwertuj wpisany tekst na małe litery

ES_MULTILINE

Flaga umożliwia wpisywanie w kontrolce wielu wierszy tekstu

ES_NUMBER

Zezwalaj na wpisywanie jedynie liczb

ES_PASSWORD

Tekst wpisany w kontrolce zostanie zastąpiony znakami *

ES_READONLY

Tekst wpisany w kontrolce będzie przeznaczony jedynie do odczytu

ES_RIGHT

Tekst zostanie wyrównany do prawej strony, jeżeli kontrolka została stworzona z flagą
ES_MULTILINE

ES_UPPERCASE

Wpisane w kontrolce litery konwertuj na wielkie

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

9 z 18

2009-03-14 15:43

background image

ES_WANTRETURN

Dotyczy kontrolek wielowierszowych. Po zastosowaniu tej flagi naciśnięcie klawisza Enter
przenosi kursor do kolejnego wiersza

Tabela 12.6. Flagi używane z kontrolką LISTBOX

Flaga

Krótki opis

LBS_DISABLENOSCROLL

Wyświetla nieaktywny, pionowy pasek przewijania

LBS_EXTENDEDSEL

Zezwala na zaznaczenie wielu wierszy z użyciem klawisza Shift

LBS_MULTICOLUMN

Zezwala na wyświetlanie w komponencie kilku kolumn

LBS_SORT

Automatyczne sortowanie kolumn

Więcej informacji na temat flag znajdziesz w pomocy WinAPI pod hasłem CreateWindow.

Obsługa zdarzeń

Umiemy już tworzyć formularze i umieszczać na nich kontrolki WinAPI. Kolejnym krokiem jest obsługa zdarzeń
(np. kliknięcia obiektu). Pierwszym krokiem będzie nadanie kontrolce jakiegoś unikalnego identyfikatora.

CreateWindow

(

'BUTTON'

,

PCHar

(

'Przycisk nr: '

+

IntToStr

(

i

))

, WS_CHILD

or WS_VISIBLE,

100

,

100

+

i *

30

,

120

,

25

, Wnd,

100

,

hInstance,

nil

)

;

W tym wypadku nadaliśmy kontrolce identyfikator nr 100. Od tego momentu podczas kliknięcia przycisku
będziemy musieli odbierać komunikat WM_COMMAND i ? zależnie od numeru ID ? odpowiednio reagować:

WM_COMMAND:

if wPar =

100

then MessageBox

(

Wnd,

'Nacisnąłeś!'

,

''

, MB_OK

)

;

Na takiej samej zasadzie możesz kontrolować naciśnięcie wszystkich przycisków ? ważne jest tylko, aby numery
ID różniły się.

W powyższym przykładzie skorzystałem z instrukcji if, lecz przy większej liczbie instrukcji wygodniej będzie
zastosować case.

Oto zmodyfikowana procedura okienkowa z poprzedniego programu:

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

var
i :

Integer

;

begin
{ na początku zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

WM_CREATE:

begin

{ w pętli umieszczamy kilka przycisków, każdemu z nich nadając kolejny identyfikator -
poczynając od 100 }

for I :=

1

to

5

do

CreateWindow

(

'BUTTON'

,

PCHar

(

'Przycisk nr: '

+

IntToStr

(

i

))

, WS_CHILD

or WS_VISIBLE,

100

,

100

+ i *

30

,

120

,

25

,

Wnd,

100

+ i, hInstance,

nil

)

;

end;

WM_COMMAND: // obsługa kliknięcia przycisku

begin

case wPar of // sprawdź, czy w Par jest od 101 do 105

101

..

105

: MessageBox

(

Wnd,

PChar

(

'Witaj!, nacisnąłeś przycisk nr '

+

IntToStr

(

wPar ?

100

)

+

'!'

)

,

':?)'

,

MB_OK + MB_ICONINFORMATION

)

;

end;

end;

WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

Jak widać, za każdą iteracją pętli nowa kontrolka zostaje utworzona ze zmienionym numerem ID. Po
uruchomieniu aplikacji i naciśnięciu przez użytkownika przycisku do programu zostaje wysłany komunikat
WM_COMMAND

z parametrem wPar, który zawiera numer ID przycisku. Na tej podstawie możemy odpowiednio

zareagować ? w tym wypadku poprzez wyświetlenie komunikatu.

Pełen kod źródłowy powyższego programu możesz znaleźć na płycie CD-ROM w katalogu ..listingi/12
/Wm_Command.

Uchwyty do kontrolek

Po prawidłowym utworzeniu kontrolki funkcja CreateWindow zwraca jej uchwyt w postaci typu HWND. Np.:

Edit := CreateWindow

(

'EDIT'

,

''

, WS_CHILD

or WS_VISIBLE or WS_BORDER,

10

,

10

,

100

,

25

, Wnd,

0

,

hInstance,

nil

)

;

Teraz mając uchwyt takiej kontrolki, możemy wysyłać do niej komunikaty. Przykładowo chcąc pobrać tekst z
kontrolki EDIT, musimy skorzystać z funkcji GetWindowText:

GetWindowText

(

Edit, Buffer,

SizeOf

(

Buffer

))

; // pobierz tekst z edita

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

10 z 18

2009-03-14 15:43

background image

Pierwszym parametrem tej funkcji musi być uchwyt kontrolki, z której chcemy pobrać tekst. Drugi parametr ?
Buffer ? to np. łańcuch o takiej postaci:

var
Buffer :

array

[

0

..

128

]

of

char

;

Pełny kod programu znajduje się w listingu 12.4.

Listing 12.4. Pełny kod programu

{
Copyright (c) 2002 by Adam Boduch
}

program PMsg;

uses
Windows,
Messages;

var
Edit : THandle;

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

var
Buffer :

array

[

0

..

128

]

of

char

;

begin
{ na początku zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

WM_CREATE:

begin

Edit := CreateWindow

(

'EDIT'

,

''

, WS_CHILD

or WS_VISIBLE or WS_BORDER,

10

,

10

,

100

,

25

,

Wnd,

0

, hInstance,

nil

)

;

CreateWindow

(

'BUTTON'

,

'OK'

, WS_CHILD

or WS_VISIBLE,

150

,

10

,

120

,

25

, Wnd,

101

,

hInstance,

nil

)

;

end;

WM_COMMAND:

if wPar =

101

then

begin

GetWindowText

(

Edit, Buffer,

SizeOf

(

Buffer

))

; // pobierz tekst z parametru Edit

MessageBox

(

Wnd, Buffer,

'EDIT'

, MB_OK

)

; // wyświetl w okienku

SendMessage

(

Wnd, WM_SETTEXT,

0

,

Longint

(

@Buffer

))

; // ustaw nową wartość Caption

end;

WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

var
Wnd: TWndClass; // klasa okna
Msg: TMsg;

begin

with Wnd do

begin

lpfnWndProc := @WndProc; // funkcja okienkowa
hInstance := hInstance;
lpszClassName :=

'My1stApp'

; // klasa

hbrBackground := COLOR_WINDOW; // kolor tła

end;

RegisterClass

(

Wnd

)

; // zarejestruj nową klasę

CreateWindow

(

'My1stApp'

,

'Server App'

,

WS_VISIBLE

or WS_TILEDWINDOW,

300

,

300

,

300

,

70

,

0

,

0

, hInstance,

NIL

)

;

while GetMessage

(

msg,

0

,

0

,

0

)

do

begin

TranslateMessage

(

msg

)

;

DispatchMessage

(

msg

)

;

end;

end.

W pierwszej kolejności po naciśnięciu przycisku pobierana zostaje wartość wpisana w kontrolce EDIT. Teraz
wystarczy już tylko wyświetlić zawartość zmiennej Buffer. Następnie program ustawia nową wartość dla okna
formularza (można powiedzieć, że to jest właściwość Caption):

SendMessage

(

Wnd, WM_SETTEXT,

0

,

Longint

(

@Buffer

))

;

Chciałem przy okazji zaprezentować sposób wysyłania komunikatów do kontrolek. W tym celu do okna należy
przekazać komunikat WM_SETTEXT. Drugi parametr natomiast musi być wskazaniem tekstu, który ma zostać
umieszczony w oknie.

Tworzenie bardziej zaawansowanych kontrolek

Aby możliwe było tworzenie bardziej zaawansowanych kontrolek (takich, jak komponenty typu TProgressBar
czy TListView), należy do listy uses dodać moduł CommCtrl. Operować tymi komponentami możemy tylko
poprzez komunikaty. Ich spis możesz znaleźć w pliku CommCtrl.pas. Znaczenie poszczególnych komunikatów
jest bardzo intuicyjne. Cóż bowiem wykonuje komunikat PBM_SETPOST? Można się domyśleć, że ustawia nową
pozycję w komponencie.

Jeżeli uruchomisz program z użyciem biblioteki CommCtrl, a na ekranie nadal widnieć będzie
?czysty? formularz (tzn. komponent nie zostanie utworzony), to wówczas konieczne będzie
wywołanie procedury InitCommonControls. Procedura ta inicjuje odpowiednią bibliotekę DLL.
Najlepiej tę procedurę wywołać tuż po utworzeniu nowej klasy w sekcji begin..end.

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

11 z 18

2009-03-14 15:43

background image

Przykładowo ? utworzenie nowej kontrolki ? la TProgressBar wygląda następująco:

CreateWindow

(

'msctls_progress32'

,

''

, WS_CHILD

or WS_VISIBLE,

100

,

10

,

350

,

20

, Wnd,

0

,

hInstance,

nil

)

;

Decydujące znaczenie ma tutaj parametr msctls_progress32. Spis wszystkich parametrów kluczowych dla
utworzenia komponentu możesz znaleźć w pliku CommCtrl.pas. Po utworzeniu komponentu można wysyłać do
niego komunikaty ? np. dotyczące zmiany pozycji:

for i :=

0

to

100

do

begin

Sleep

(

50

)

;

SendMessage

(

ProgressBar, PBM_SETPOS, i,

0

)

;

end;

Jest to zatem pętla od jednego do stu z przerwami pomiędzy kolejnymi iteracjami, wynoszącymi 50 milisekund.
Podczas każdorazowego wykonania pętli do komponentu jest wysyłany komunikat PBM_SETPOS. Parametr lParam
funkcji SendMessage zawiera nową wartość (pozycję) paska postępu. Cały ten kod umieścimy w programie
obsługi komunikatu WM_PAINT (listing 12.5.)

Listing 12.5. Pełny kod programu

{
Copyright (c) 2002 by Adam Boduch
}

program Ctrl;

uses
Windows,
CommCtrl,
Messages;

var ProgressBar : HWND;

function WndProc

(

Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM

)

: LRESULT;

stdcall;

var
i :

Integer

;

begin
{ na początku zwracamy wartość 0 ? meldunek jest przetwarzany }

Result

:=

0

;

case uMsg of

WM_CREATE:

begin

// umieść komponent ProgressBar i zwróć uchwyt
ProgressBar := CreateWindow

(

'msctls_progress32'

,

''

, WS_CHILD

or WS_VISIBLE,

100

,

10

,

350

,

20

, Wnd,

0

, hInstance,

nil

)

;

end;

WM_PAINT: // obsługa komunikatu WM_PAINT

begin

for i :=

0

to

100

do

begin

Sleep

(

50

)

; // odczekaj 50 milisekund

SendMessage

(

ProgressBar, PBM_SETPOS, i,

0

)

; // wyślij komunikat do komponentu

end;

Halt

(

1

)

; // zamknij program

end;

WM_DESTROY: PostQuitMessage

(

0

)

;

else

Result

:= DefWindowProc

(

Wnd, uMsg, wPar, lPar

)

;

end;

end;

var
Wnd: TWndClass; // klasa okna
Msg: TMsg;

begin

with Wnd do

begin

lpfnWndProc := @WndProc; // funkcja okienkowa
hInstance := hInstance; lpszClassName :=

'My1stApp'

; // klasa

hbrBackground := COLOR_WINDOW; // kolor tła
hIcon := LoadIcon

(

0

, IDI_APPLICATION

)

; // domyślna ikona

hCursor := LoadCursor

(

0

, IDC_ARROW

)

; // domyślny kursor

end;

RegisterClass

(

Wnd

)

; // zarejestruj nową klasę

InitCommonControls;

// stwórz formularz...
CreateWindow

(

'My1stApp'

,

'Aplikacja z wykorzystaniem modułu CommCtrl.pas'

,

WS_VISIBLE

or WS_TILEDWINDOW,

300

,

300

,

500

,

300

,

0

,

0

, hInstance,

NIL

)

;

while GetMessage

(

msg,

0

,

0

,

0

)

do

begin

TranslateMessage

(

msg

)

;

DispatchMessage

(

msg

)

;

end;

end.

Pozostałe kontrolki

Nazwy pozostałych kontrolek, z jakich możesz skorzystać w swoich programach, zawarte są w pliku
CommCtrl.pas. Tam również możesz znaleźć listę komunikatów związanych z konkretnym komponentem. W
tabeli 12.7 prezentuję komponenty, których możesz użyć w swoich programach w API, wraz z ich
odpowiednikami w VCL.

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

12 z 18

2009-03-14 15:43

background image

Tabela 12.7. Kontrolki z biblioteki CommCtrl.dll

Identyfikator kontrolki

Nazwa kontrolki

Odpowiednik VCL

ToolbarWindow32

Pasek narzędziowy

TToolBar

msctls_statusbar32

Pasek aplikacji

TStatusBar

msctls_trackbar32

Pasek przewijania

TTrackBar

msctls_updown32

Pasek góra-dół

TUpDown

msctls_progress32

Pasek postępu

TProgressBar

SysListView32

Lista pozycji

TListView

SysTreeView32

Drzewo obiektów

TTreeView

ComboBoxEx32

Kontrolka Combo

TComboBoxEx

SysTabControl32

System zakładek

TTabControl

SysAnimate32

Animacje systemowe

TAnimate

SysMonthCal32

Kalendarz

TMonthCalendar

SysDateTimePick32

Prezentuje datę i czas

TDateTimePicker

SysIPAddress32

Podaje adres IP komputera.

brak odpowiednika

SysPager

System stron

TPageControl

Wyświetlanie grafiki

We wcześniejszych rozdziałach miałeś okazję zapoznać się z funkcjami operującymi na grafice czy też
wyświetlającymi tekst. Poznałeś także klasę TCanvas, która owe zadanie znacznie upraszczała. Funkcje API
umożliwiające rysowanie lub wyświetlanie grafiki są bardzo podobne do funkcji z klasy TCanvas. Różnica polega
jedynie na liczbie parametrów.

Rysowanie w WinAPI

Przypominam, że rysowanie czegokolwiek powinno odbyć się po wywołaniu komunikatu WM_PAINT. Wiadomo, że
okno w Windows może podlegać różnym zdarzeniom, takim jak: minimalizacja, możliwość zasłonięcia przez
inne okno itp. System nie przechowuje obrazu ekranu w pamięci, lecz odpowiedzialna jest za to sama aplikacja.

Po odsłonięciu okna i przywróceniu go na pierwszy plan do aplikacji wysyłany jest komunikat WM_PAINT ? do nas
należy obsłużenie tego komunikatu.

Kontekst urządzenia graficznego

Wszystkie funkcje operujące na WinAPI wymagają podania pierwszego parametru, który jest tzw. kontekstem
urządzenia (Device Context). Jest to pewna struktura danych, opisująca różne parametry rysowania ? czcionkę,
grubość i kolor linii itp. Takie ustawienia są różne dla każdego programu uruchomionego w systemie, a my w
swoich aplikacjach będziemy musieli pobierać uchwyt do owego kontekstu:

DCHandle := GetDC

(

Wnd

)

;

Od tej pory mamy już uchwyt, który będzie trzeba podawać przy każdej funkcji operującej na grafice. Po
zakończeniu malowania należy ten uchwyt zwolnić, korzystając z polecenia ReleaseDC:

ReleaseDC

(

Wnd, DCHandle

)

;

Za pomocą funkcji GetDC uzyskujemy uchwyt, dzięki któremu możemy malować po całym
obszarze roboczym programu. Nie mamy natomiast możliwości rysowania na pasku
tytułowym okna ? do tego będzie nam potrzebna funkcja GetWindowDC.

Obsługa WM_PAINT

Istnieje lepsza metoda dostarczania kontekstu urządzenia ? rekord TPaintStruct. Rekord TPaintStruct
dostarcza oprócz kontekstu urządzenia także informacje, które można wykorzystać podczas obsługi komunikatu
WM_PAINT

. Namalowanie czegoś na formularzu opiera się na wywołaniu metody BeginPaint oraz ? po

zakończeniu ? EndPaint:

WM_PAINT:

begin

DC := BeginPaint

(

Wnd, PS

)

;

TextOut

(

DC,

10

,

10

,

'Delphi 7'

,

Length

(

'Delphi 7'

))

;

EndPaint

(

Wnd, PS

)

;

end;

Wcześniej jednak należy zadeklarować zmienne PS oraz DC:

var
PS : TPaintStruct;
DC : HDC; // uchwyt

Funkcja TextOut realizuje ? podobnie jak funkcja o tej samej nazwie z klasy TCanvas ? rysowanie tekstu.
Pierwszym parametrem musi być uchwyt do kontekstu urządzenia. Kolejne dwa parametry to współrzędne
rysowanego tekstu. Trzeci parametr to tekst, który zostanie narysowany na formularzu, a ostatni ? długość
tekstu. Rysunek 12.4 prezentuje program po uruchomieniu.

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

13 z 18

2009-03-14 15:43

background image

Rysunek 12.4. Tekst narysowany metodą TextOut

Zmiana koloru tła

Na rysunku 12.4 widzisz, że dotychczasowy efekt działania funkcji TextOut nie jest zbyt interesujący. Napis
jest wyświetlany na białym tle. Aby to zmienić, można ustawić przezroczyste tło, używając w tym celu funkcji
SetBkMode

:

SetBkMode

(

DC, TRANSPARENT

)

;

Pierwszy parametr musi być kontekstem urządzenia, a drugi to flaga informująca o tym, że tło będzie
przezroczyste (TRANSPARENT).

W dość prosty sposób można zmienić również kolor wyświetlanego tekstu. Wystarczy zastosować funkcję
SetTextColor

. Pierwszym parametrem tej funkcji musi być oczywiście kontekst urządzenia. Drugi parametr

musi określać kolor tekstu w postaci RGB (Reed Green Blue), czyli kombinacji trzech kolorów: czerwonego,
zielonego i niebieskiego ? np.:

SetTextColor

(

DC, RGB

(

0

,

100

,

150

))

;

Ładowanie i wyświetlanie bitmapy

Załóżmy, że w zasobach programu umieszczona jest bitmapa o nazwie ID_BITMAP. Przy wykorzystaniu VCL
załadowanie bitmapy do komponentu TImage zajęłoby chwilę ? wystarczyłby jeden wiersz kodu:

Image.

Picture

.

Bitmap

.

LoadFromResourceName

(

hInstance,

'ID_BITMAP'

)

;

Chcąc skorzystać z funkcji API, musimy poświęcić na to nieco więcej czasu i napisać więcej kodu:
WM_PAINT

:

begin

DC := BeginPaint

(

Wnd, PS

)

;

Bitmap := LoadBitmap

(

hInstance,

'ID_BITMAP'

)

;

_Bitmap := CreateCompatibleDC

(

DC

)

;

SelectObject

(

_Bitmap, Bitmap

)

;

BitBlt

(

dc,

10

,

10

,

14

,

14

, _Bitmap,

0

,

0

, SRCCOPY

)

;

DeleteDC

(

_Bitmap

)

;

EndPaint

(

Wnd, PS

)

;

end;

Samo załadowanie jest proste, gdyż używamy tutaj funkcji LoadBitmap, która zwraca bitmapę w postaci
zmiennej HBITMAP (odpowiednik klasy TBitmap). Następnym krokiem jest stworzenie pamięciowego kontekstu
urządzenia (CreateCompatibleDC), na którym zostanie narysowana bitmapa. Kolejny krok to wybranie
właściwego kontekstu za pomocą funkcji SelectObject. Wreszcie samo narysowanie bitmapy następuje poprzez
funkcję BitBlt. Pierwszy parametr owej funkcji to uchwyt kontekstu, na którym zostanie narysowana bitmapa.
Kolejne dwa parametry to X i Y, współrzędne miejsca wyświetlania obrazka. Rozmiar rysowanej bitmapy
określają dwa kolejne parametry. Jeszcze inne dwa parametry określają pozycję X i Y lewego górnego rogu
obrazka oraz stopień jego wyświetlania. Ostatni parametr określa sposób przedstawienia bitmapy ? w tym
wypadku kopiowanie ze źródła do miejsca przeznaczenia.

Najlepszym sposobem sprawdzenia działania owych parametrów jest przetestowanie ich w praktyce.
Nim skompilujesz swój program, zadeklaruj w nim następujące zmienne:

var
Bitmap : HBITMAP;
_Bitmap : HDC;

Ładowanie zasobów

W rozdziale 10. była mowa o wykorzystaniu zasobów do przechowywania w pliku wykonywalnym różnych
danych ? począwszy od grafiki, a na innych plikach wykonywalnych skończywszy. W tym podpunkcie pokażę, w
jaki sposób skorzystać z tych zasobów, nie używając przy tym klasy TResourceStream.

Korzystając z zasobów, można w WinAPI napisać swój własny instalator, który będzie ?przechowywał? w sobie
pliki instalacyjne. Taki przykładowy instalator możesz znaleźć na płycie CD-ROM w katalogu ../listingi
/12/Install. W katalogu z projektem znajdziesz również skompilowaną wersję projektu ? plik Install.exe
(rysunek 12.5). Po uruchomieniu programu instalacyjnego na dysku zostanie zainstalowany program, który
kiedyś napisałem (lecz to jest w tej chwili nie istotne).

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

14 z 18

2009-03-14 15:43

background image

Rysunek 12.5. Instalator wykonany w WinAPI

Skompilowane zasoby

Tworzenie zasobów za pomocą programu brcc32.exe wygląda tak samo, jak to przedstawiałem w rozdziale 10. ?
np. w przypadku mojego instalatora plik files.rc wygląda tak:

MAILBOXES RCDATA "Mailboxes.exe"
SETUP RCDATA "setup.dll"
MAILCNT RCDATA "Mailboxes.cnt"
MAILHLP RCDATA "Mailboxes.hlp"
README RCDATA "Readme.html"
SAMPLE RCDATA "sample.txt"
DEFAULT RCDATA "default.mbx"
UNINSTALL RCDATA "Odinstaluj.exe"

Tak skonstruowany plik *.rc pozwoli na włączenie do gotowego zasobu (*.res) powyżej przedstawionych plików.

W rozdziale 10. nie wspomniałem o jednej kwestii ? mianowicie o możliwości tworzenia bardziej
zaawansowanych zasobów, np. formularza:

LICENCJA DIALOGEX 42, 8, 271, 133
STYLE DS_MODALFRAME | DS_CENTER | DS_3DLOOK | DS_SETFOREGROUND | WS_POPUP |
WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CLIENTEDGE
CAPTION "Instalacja programu"
FONT 8, "MS Sans Serif"
BEGIN
ICON "a", a, 11, 9, 21, 20
LTEXT "Najnowszą wersję programu MailBoxes możesz zawsze znaleźć na stronie
www.4programmers.net",
a, 37, 11, 221, 20
DEFPUSHBUTTON "Instaluj", 102, 101, 100, 101, 14
PUSHBUTTON "Wyjście", 103, 208, 100, 47, 14
GROUPBOX "Gdzie zainstalować program?", a, 10, 59, 247, 32
EDITTEXT 106, 16, 72, 233, 14, ES_AUTOHSCROLL
CONTROL "BAR", BAR, "msctls_progress32", 0x0 | WS_CLIPSIBLINGS,
14, 42, 241, 11
END

Pisanie tego ręcznie raczej nie ma sensu ? ja używałem pakietu Microsoft Visual Studio, który oferuje tworzenie
zasobów. Ty jednak możesz skorzystać z darmowych narzędzi dostępnych w Internecie.

Wykorzystanie zasobów

Ażeby skorzystać z naszych zasobów, będziemy zmuszeni zastosować funkcje WinAPI, których do tej pory nie
używaliśmy ? np. LoadResource i FindRecource. Najpierw jednak należy zająć się przedstawieniem formularza
instalacyjnego.

Wyświetlenie formularza

Za wyświetlenie formularza znajdującego się w zasobach odpowiada funkcja DialogBox:

function DialogBox

(

hInstance: HINST; lpTemplate:

PChar

;

hWndParent: HWND; lpDialogFunc: TFNDlgProc

)

:

Integer

;

Pierwszy parametr musi być wskazaniem modułu, w którym znajdują się zasoby ? my w tym miejscu podajemy
wartość hInstance. Drugi parametr musi być nazwą szablonu, który chcemy wyświetlić. Parametr trzeci
(hWndParent) stanowi uchwyt do okna macierzystego; jako że nasze okno będzie oknem macierzystym,
wpisujemy w tym miejscu cyfrę 0. Ostatni parametr to wskazanie procedury, która będzie obsługiwać zdarzenia
naszego formularza:

DialogBox

(

hInstance,

'LICENCJA'

,

0

, @DlgWindowProc

)

;

Funkcja DlgWindowProc, którą podałem w ostatnim parametrze, jest zwykłą funkcją okienkową ? musi
odpowiadać na przychodzące do aplikacji komunikaty.

Zamknięcie okna (zakończenie działania aplikacji) zrealizujemy za pomocą polecenia EndDialog:

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

15 z 18

2009-03-14 15:43

background image

EndDialog

(

wnd,

0

)

;

Ustawianie wartości komponentów formularza

Mimo że formularz wykorzystany w programie jest jedynie skryptem, posiada on także komponenty. Podczas
ustawiania tych komponentów przydzieliłem każdemu z nich osobny identyfikator (ID), do którego będziemy
się odwoływać podczas wykonywania funkcji:

SetDlgItemText

(

wnd,

106

,

'C:\Mailboxes 1.53'

)

;

Przykładowo funkcja SetDlgItemText powoduje ustawienie nowej wartości kontrolki. W pierwszym parametrze
wpisujemy uchwyt okna, a w drugim ID kontrolki. Parametr ostatni to tekst, który ma zostać umieszczony w
obiekcie.

LockResource, LoadResource, FindResource

Załadowanie zasobów (tekstu licencji) do kontrolki może się wydać trochę skomplikowane, gdyż trzeba się
posłużyć aż trzema funkcjami naraz: LockResource, LoadResource i FindResource.

SetDlgItemText

(

wnd,

101

,

LockResource

(

LoadResource

(

hinstance,FindResource

(

hinstance,

'LICENCJA'

,

'TXT'

))))

;

Pierwsza funkcja ? LockResource ? zwraca wskaźnik do pierwszego bajtu zasobów, jednak wymaga podania
uchwytu do zasobów. Ten globalny uchwyt jest natomiast zwracany przez funkcję LoadResource, która w
drugim parametrze wymaga podania wskazania ładowanego zasobu. Tutaj pomoże nam funkcja FindResource,
w której parametrach wystarczy podać typ oraz nazwę zasobu.

Zapisywanie plików na dysku

Chcąc zastąpić klasę TResourceStream, jesteśmy zmuszeni skorzystać z funkcji LoadResource oraz
FindResource

. Najpierw w swoim instalatorze zadeklaruj tablicę plików, które są instalowane:

{ oto elementy umieszczone w zasobach }
const Tablica : array

[

0

..

7

]

of _DATA =

((

Files:

'Mailboxes.exe'

; FName:

'MAILBOXES'

)

,

(

Files:

'setup.dll'

; FName:

'SETUP'

)

,

(

Files:

'Mailboxes.cnt'

; FName:

'MAILCNT'

)

,

(

Files:

'Mailboxes.hlp'

; FName:

'MAILHLP'

)

,

(

Files:

'Readme.html'

; FName:

'README'

)

,

(

Files:

'Sample.txt'

; FName:

'SAMPLE'

)

,

(

Files:

'default.mbx'

; FName:

'DEFAULT'

)

,

(

Files:

'Odinstaluj.exe'

; FName:

'UNINSTALL'

))

;


Pierwszy element tej tablicy to nazwa pliku, który ma zostać utworzony na dysku; drugi to wskazanie nazwy
zasobu. Instalacja (wyodrębnianie) poszczególnych elementów może wyglądać tak:

For I:=

Low

(

Tablica

)

to

High

(

Tablica

)

do

begin

AssignFile

(

Ouff, PC + Tablica

[

i

]

.

Files

)

; // stwórz plik...

Rewrite

(

Ouff,

1

)

;

{ odnajdź w zasobach zasób i przypisz go zmiennej Fres }
Fres := FindResource

(

hInstance, Tablica

[

i

]

.

FName

, RT_RCDATA

)

;

{ do pliku zapisz dane z wyciągniętych zasobów }

BlockWrite

(

Ouff, LockResource

(

LoadResource

(

hInstance, Fres

))

^, SizeofResource

(

hinstance,

Fres

))

;

Closefile

(

ouff

)

; // zamknij plik

end;

Posłużyłem się tutaj funkcjami operującymi na plikach, które szczegółowo omówiłem w rozdziale 7. Po
zlokalizowaniu konkretnego zasobu (FindResource) następuje jego zapisanie do pliku (BlockWrite). Pełny kod
źródłowy znajduje się w listingu 12.6.

Listing 12.6. Kod źródłowy instalatora

{
Copyright (c) 2001 by Adam Boduch [http://programowanie.of.pl]
}

program setup;

uses
Windows,
Messages;

{$R FILES.RES} // <--- pliki, które zostaną zainstalowane
{$R RESOURCE.RES}
// <---- bitmapa ( dodatkowe pliki )

type
{
rekord zawiera dwa elementy. Pierwszym jest nazwa pliku umieszczonego w zasobach
? np. SFP, a drugim elementem jest nazwa pliku, który zostanie zapisany na
dysku ? np: sfp.jpg
}
_DATA =

packed record

Files:

String

;

FName:

PChar

;

end;

{ oto elementy umieszczone w zasobach }
const Tablica : array

[

0

..

7

]

of _DATA =

((

Files:

'Mailboxes.exe'

; FName:

'MAILBOXES'

)

,

(

Files:

'setup.dll'

; FName:

'SETUP'

)

,

(

Files:

'Mailboxes.cnt'

; FName:

'MAILCNT'

)

,

(

Files:

'Mailboxes.hlp'

; FName:

'MAILHLP'

)

,

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

16 z 18

2009-03-14 15:43

background image

(

Files:

'Readme.html'

; FName:

'README'

)

,

(

Files:

'Sample.txt'

; FName:

'SAMPLE'

)

,

(

Files:

'default.mbx'

; FName:

'DEFAULT'

)

,

(

Files:

'Odinstaluj.exe'

; FName:

'UNINSTALL'

))

;

var KeyHandle : HKEY;
Uninstall :

PChar

;

const Name :

PChar

=

'Mailboxes v. 1.5.3'

;

(*************************************************************************)

function DlgWindowProc

(

Wnd: hWnd; Msg: UINT; DlgWParam: WPARAM; DlgLParam: LPARAM

)

:

boolean

;

stdcall;
var
Fres:

Integer

;

Ouff:

File;

Buff:

array

[

0

..

254

]

of

char

;

PC :

String

;

I :

Integer

;

label Next;
begin

result

:=

true;

case Msg of

WM_INITDIALOG:

begin

SetDlgItemText

(

wnd,

101

,

LockResource

(

LoadResource

(

hinstance,FindResource

(

hinstance,

'LICENCJA'

,

'TXT'

))))

;

SetDlgItemText

(

wnd,

106

,

'C:\Mailboxes 1.53'

)

;

end;

WM_CLOSE: EndDialog

(

wnd,

0

)

;

wm_activate: SendDlgItemMessage

(

wnd,

101

, EM_SETSEL, ?

1

,

0

)

;

WM_COMMAND:

begin

if LOWORD

(

DlgWParam

)

=

103

then EndDialog

(

wnd,

0

)

;

if LOWORD

(

DlgWParam

)

=

102

then

begin

{ pobranie ścieżki, w której ma zostać zainstalowany program }
GetDlgItemText

(

wnd,

106

, Buff,

SizeOf

(

Buff

))

;

PC := Buff;

{ sprawdzenie, czy na końcu znajduje się znak \ }

if PC

[

Length

(

PC

)]

<>

'\'

then PC := PC +

'\'

else PC := PC;

Uninstall :=

PChar

(

PC +

'Odinstaluj.exe'

)

;

{ otwarcie rejestru i klucza }
RegOpenKeyEx

(

HKEY_LOCAL_MACHINE,

PChar

(

'Software\Microsoft\Windows\CurrentVersion

\Uninstall'

)

,

0

,

KEY_ALL_ACCESS, KeyHandle

)

;

{ stworzenie nowej wartości }
RegCreateKey

(

KeyHandle,

'Mailboxes'

, KeyHandle

)

;

RegSetValueEx

(

KeyHandle,

'DisplayName'

,

0

, REG_SZ,

Name,

SizeOf

(

Name

))

;

RegSetValueEx

(

KeyHandle,

'UninstallString'

,

0

, REG_SZ, Uninstall,

SizeOf

(

Uninstall

))

;

{ sprawdzenie, czy użytkownik nie wpisał tylko litery partycji ? jeżeli nie, należy
utworzyć dodatkowo katalog }

if

Length

(

PC

)

<=

3

then goto Next else CreateDirectory

(

PChar

(

PC

)

,

nil

)

;

Next:

{ instaluj poszczególne elementy }

For I:=

Low

(

Tablica

)

to

High

(

Tablica

)

do

begin

AssignFile

(

Ouff, PC + Tablica

[

i

]

.

Files

)

; // stworz plik...

Rewrite

(

Ouff,

1

)

;

{ odnajdź w zasobach zasób i przypisz go do zmiennej Fres }
Fres := FindResource

(

hInstance, Tablica

[

i

]

.

FName

, RT_RCDATA

)

;

{ do pliku zapisz dane z "wyciągniętych" zasobów }

BlockWrite

(

Ouff, LockResource

(

LoadResource

(

hInstance, Fres

))

^,

SizeofResource

(

hinstance, Fres

))

;

Closefile

(

ouff

)

; // zamknij plik

end;

MessageBox

(

0

,

'Instalacja przebiegła pomyślnie!'

,

':)'

, MB_OK + MB_ICONINFORMATION

)

;

PostQuitMessage

(

0

)

; // zakończ program...

end;

end;

else

result

:=

false;

end;

end;

begin

if MessageBox

(

0

,

'Za chwilę odbędzie się instalacja programu Mailboxes v. 1.53. Czy chcesz

kontynuować?'

,

'Mailboxes ? instalacja'

, MB_YESNO + MB_ICONINFORMATION

)

= ID_Yes

then

begin

DialogBox

(

hInstance,

'LICENCJA'

,

0

, @DlgWindowProc

)

;

end;

end.

Podsumowanie

Programowanie w czystym WinAPI może być niewygodne, a nawet dość trudne, ale nie da się ukryć, że
zapewnia większą kontrolę nad programem i daje większe możliwości, których niekiedy brak w bibliotece VCL.

Załączniki:

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

17 z 18

2009-03-14 15:43

background image

« Aplikacje sieciowe

Spis treści

COM i ActiveX »

Listingi_12.zip

(599.11 kB)

Więcej informacji

Delphi 2005. Kompendium
programisty

Adam Boduch

Format: B5, stron: 1048
oprawa twarda
Zawiera CD-ROM

©

Helion 2003. Autor:

Adam Boduch

. Zabrania się rozpowszechniania tego tekstu bez zgody autora.

Kategoria

:

Kompendium

Ostatnia modyfikacja

20-06-2006 11:36

Ostatni autor

Coldpeer

Ilość wyświetleń

17378

Wersja

2

Dodaj komentarz

Delphi :: Kompendium :: Rozdział 12 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_12

18 z 18

2009-03-14 15:43


Wyszukiwarka

Podobne podstrony:
Delphi Kompendium Roz12
Delphi Kompendium Roz8
Delphi Kompendium Roz10
Delphi Kompendium Roz6
Delphi Kompendium Roz5
Delphi Kompendium Roz14
Delphi 7 Kompendium programisty
Delphi 7 Kompendium programisty del7ko 2
Delphi 7 Kompendium programisty
Delphi Kompendium programisty 2
Delphi Kompendium Roz5
Delphi 7 Kompendium programisty
Delphi 7 Kompendium programisty 2
Delphi Kompendium programisty
Delphi Kompendium Roz6
Delphi Kompendium programisty 2
Delphi 7 Kompendium programisty del7ko
Delphi Kompendium programisty delpbb

więcej podobnych podstron