Blog literacki, portal erotyczny - seks i humor nie z tej ziemi
LEKCJA 42: KOMPILATORY "SPECJALNIE DLA Windows".
________________________________________________________________
Z tej lekcji dowiesz się, czym różnią się kompilatory
przeznaczone dla pracy w środowisku Windows.
________________________________________________________________
W IDE i w sposobie zachowania zaszły istotne zmiany. Posługując
się Turbo C++ z pakietu BORLAND C++ 3.0 lub BCW z pakietu 3.1
możemy korzystać z uroków i usług Windows szerzej niż do tej
pory. Możemy otwierać wiele okien i uruchamiać bezpośrednio z
poziomu IDE okienkowe aplikacje. W głównym menu kompilatora
zaszły pewne zmiany (sygnalizujące obiektowo- i okienkowo -
zorientowaną ewolucję pakietów Borlanda), na które warto zwrócić
uwagę.
Zniknęło menu Debug (co wcale nie oznacza, że nie możemy
korzystać z Debuggera), pojawiło się natomiast nowe menu Browse
(przeglądanie). Rozkazy, których tradycyjnie szukaliśmy w menu
Debug zostały rozrzucone do innych menu. I tak:
Menu Compile zawiera:
Compile (kompilacja do *.OBJ),
Make (kompilacja i konsolidacja do *.EXE),
Link (konsolidacja bez powtórnej kompilacji),
Build all (konsolidacja wszystkich modułów),
Information... (informacja o przebiegu kompilacji),
Remove messages (usuwanie komunikatów z pliku wynikowego)
Menu Run zawiera:
Run (uruchomienie i ewentualna rekompilcja),
Arguments... (argumenty uruchomieniowe z wiersza rozkazu),
Debugger (zamiast w Debug - TU!)
Debugger arguments... (argumenty dla Debuggera)
Menu Project zawiera:
Open project - otwórz (nowy lub istniejący) plik projektu,
Close project - zamknij projekt,
Add item... - dodaj element (plik) do projektu,
Delete item - usuń element (plik) z projektu,
Include ˙˙files... ˙˙- ˙˙podaj ˙katalog ˙zawierający ˙dodatkowe
dołączane do programu pliki nagłówkowe *.H
W menu Options (zestaw znany już z Borland C++) warto zwrócić
uwagę na pewną dodatkową możliwość. Jak wiemy z doświadczenia,
uruchamiając program często dokonujemy zmian i korekt w pliku
żródłowym *.C, czy *.CPP. Znacznie rzadziej jednak zmieniamy
zestaw dołączanych do programu plików nagłówkowych *.H. Wiemy
również, że kompilacja tych właśnie plików nagłówkowych zajmuje
często lwią część czasu całej kompilacji i konsolidacji
programu. Borland zauważył to i w okienku dialogowym:
Options | Compiler | Code generation --> Code Generation Options
umieścił opcję Pre-compiled headers (pliki nagłówkowe wstępnie
skompilowane wcześniej - i tylko jeden raz). Szczególnie w
przypadku aplikacji okienkowych może to znacznie przyspieszyć
proces uruchamiania i "szlifowania" naszych programów. Nie ma
jednak nic za darmo. Borland/Turbo C++ po skompilowaniu plików
nagłówkowych tworzy na dysku roboczy plik *.SYM nadając mu nazwę
zgodną z nazwą bieżącego projektu (jest to zwykle nazwa głównego
modułu *.CPP) i do poprawnego działania wymaga kilkadziesiąt lub
nawet kilkaset kilobajtów dodatkowej przestrzeni na dysku.
[!!!]UWAGA
________________________________________________________________
Jeśli przenosisz projekt na dyskietkę i tam kontynuujesz pracę
nad projektem, pamiętaj, że może zabraknąć miejsca na
prekompilowany plik .SYM.
________________________________________________________________
Czytelnik zechce sam sprawdzić w jakim stopniu przyspieszy to
kompilację naszego własnego programu proceduralno -
zdarzeniowego WINPZ1.CPP:
WINZ1.CPP. Jednomodułowa aplikacja proceduralno - zdarzeniowa
dla Windows.
________________________________________________________________
#include
#pragma argused
long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow )
{
WNDCLASS Okno1;
MSG komunikaty;
HWND NrOkna;
LPSTR LongPtr1 = "Okno 1";
LPSTR lp2 = "AM: BC++ 3..4/Reczne sterowanie (1)";
if (hPrevInstance == 0)
{
Okno1.style= CS_HREDRAW | CS_VREDRAW ;
Okno1.lpfnWndProc= WndProc;
Okno1.cbClsExtra = 0;
Okno1.cbWndExtra= 0;
Okno1.hInstance = hInstance;
Okno1.hCursor = LoadCursor(0, IDC_CROSS );
Okno1.hbrBackground= GetStockObject(WHITE_BRUSH );
Okno1.lpszMenuName= 0;
Okno1.lpszClassName= LongPtr1;
if (!RegisterClass(&Okno1))
return 0;
}
NrOkna = CreateWindow(LongPtr1, lp2, WS_VISIBLE |
WS_SYSMENU |
WS_MINIMIZEBOX | WS_VSCROLL | WS_MAXIMIZEBOX,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
ShowWindow(NrOkna, nCmdShow);
UpdateWindow(NrOkna);
while (GetMessage(&komunikaty, 0, 0, 0))
{
TranslateMessage(&komunikaty );
DispatchMessage(&komunikaty );
}
return 0;
}
long FAR PASCAL WndProc (HWND NrOkna, unsigned KomunikatWindows,
WORD wParam, LONG lParam)
{
HDC NrKontekstu;
PAINTSTRUCT struktura_graficzna;
RECT prostokat;
switch(KomunikatWindows)
{
case WM_PAINT:
{
NrKontekstu = BeginPaint(NrOkna, &struktura_graficzna);
GetClientRect(NrOkna, &prostokat);
TextOut(NrKontekstu,80,50, ": Reczne sterowanie:", 20 );
TextOut(NrKontekstu, 5,70, "Tu -->", 6);
TextOut(NrKontekstu, 5, 85, "Blad:", 5);
TextOut(NrKontekstu,75,70, "-----------------------------",
40);
TextOut(NrKontekstu,30,110, "Programowanie proceduralno -
zdarzeniowe.", 41 );
TextOut(NrKontekstu,30,135, "Szablon moze zostac rozbudowany
o inne funkcje.", 47 );
TextOut(NrKontekstu,30,180, "RECZNIE panujemy np. nad:", 25
);
TextOut(NrKontekstu,20,220, "paskiem tytulowym okna, tytulem
ikonki...", 41);
TextOut(NrKontekstu, 100, 250, "!KONIEC - [Alt]+[F4]", 20);
EndPaint(NrOkna,&struktura_graficzna);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(NrOkna,KomunikatWindows,wParam,lParam);
}
return 0;
}
Program demonstruje opisane wyżej mechanizmy, może być
uruchamiany wielokrotnie i sprowadzony do ikony. Z uwagi na brak
zdefiniowanych dodatkowych zasobów (brak w projekcie plików:
.RC - resources - zasoby
.ICO - ikona
.DEF - definicji
.PRJ lub .IDE - projektu
.DSK - konfiguracyjnego
itp.)
podczas kompilacji programu wystąpią dwa komunikaty
ostrzegawcze. Komunikaty te można zignorować.
A oto druga przykładowa aplikacja w tym samym stylu. Tym razem
funkcja okienkowa reaguje na naciśnięcie lewego klawisza myszki,
co powoduje wygenerowanie komunikatu WM_LEFTBUTTONDOWN.
Program WINZ-2.CPP
________________________________________________________________
#include
#include
#pragma argused
char napis[10];
int X, Y;
LONG FAR PASCAL WndProc (HWND, WORD, WORD, LONG);
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow )
{
WNDCLASSwndClass;
MSGmsg;
HWNDhWnd;
LPSTR Lp1 = "Mysza1";
LPSTR lp2 = "WINPZ2: Wykrywanie Lewego Klawisza
Myszki";
if (!hPrevInstance)
{
wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra= 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = 0;
wndClass.hCursor= LoadCursor(0, IDC_ARROW );
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= 0;
wndClass.lpszClassName= Lp1;
if (!RegisterClass(&wndClass))
exit(1);
}
hWnd = CreateWindow(Lp1, lp2, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg );
DispatchMessage(&msg );
}
return 0;
}
LONG FAR PASCAL WndProc (HWND hWnd, WORD Message,
WORD wParam, LONG lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;
switch(Message)
{
case WM_SIZE:
hDC = GetDC( hWnd );
TextOut(hDC, 50, 100, "Wykrywanie nacisniecia", 22);
TextOut(hDC, 50, 120, "lewego klawisza myszki.", 23);
TextOut(hDC, 20, 140, "Komunikat o zdarzeniu: ", 22);
TextOut(hDC, 20, 156, "Left Button Down - LBUTTONDOWN", 31);
TextOut(hDC, 50, 170, "Po wcisnieciu klawisza,", 23);
TextOut(hDC, 50, 190,"w biezacej pozycji kursora, pojawi sie
napis <-- Tu!.", 52);
ReleaseDC(hWnd, hDC);
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC, X,Y, napis, strlen(napis));
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
strcpy(napis,"<-- Tu !");
X = LOWORD(lParam);
Y = HIWORD(lParam);
InvalidateRect(hWnd, 0, TRUE);
UpdateWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
}
return 0;
}
Plik nagłówkowy STRING.H pojawia się ze względu na obecność
funkcji strlen() wyznaczającej długość napisu. Zmienne X i Y to
bieżące (względne) współrzędne kursora myszki w momencie
naciśnięcia klawisza. Program demonstruje następujące efekty:
X = LOWORD(lParam);
- przekazanie współrzędnej X przy pomocy parametru lParam
(LOWORD to LOw WORD of the double word - młodsze słowo podójnego
słowa).
Y = HIWORD(lParam);
Analogicznie - przekazanie współrzędnej Y (HIgh WORD of the
double word). Funkcja InvalidateRect() powoduje uznanie
prostokąnego pola za nieaktualne. Funkcja UpdateWindow()
"odświeża" okno. Dzięki temu tandemowi napis znika i pojawia się
w nowym miejscu.
PROJEKT.
Aby skompilować powyższe programy przykładowe należy:
1. Uruchomić kompilator C++.
2. Załadować do okienka edycyjnego (File | Open) plik z tekstem
żródłowym programu.
3. Wybrać rozkaz Compile z menu Compile.
Przed kompilacją i konsolidacją (jeśli był inny) ustawić sposób
tworzenia kodu wynikowego [Windows EXE].
Kompilacja przebiegnie poprawnie (pamiętaj o Opcjach i
Katalogach), mimo to pojawią się jednak dwa komunikaty
ostrzegawcze. W okienku "Compile Status" (stan/przebieg
kompilacji) pojawi się zawartość:
Lines 3832 (znakomita większość to WINDOWS.H,
prekompilacja byłaby celowa)
Warnings: 1
Errors: 0
Jeśli wybierzesz klawisz [OK] w okienku "focus" (aktywność)
zostanie przekazana do okienka komunikatów "Message" a tam
pojawi się napis:
Warning: Parameter 'lspzCmdLine' is never used.
Wskaźnik do parametrów uruchomieniowych programu (Arguments)
pobieranych z wiersza rozkazu nie został ani raz użyty w
programie. Na to nic nie możemy poradzić. Po prostu argumenty
uruchomieniowe nie są nam potrzebne. Wykonujemy więc "klik"
(przekazanie "focusa") w okienku edycyjnym i możemy przejść do
następnej czynności:
4. Konsolidacja: Compile | Link.
W okienku "Message" znów pojawi się ostrzeżenie:
Linker Warning: No module definition file specified:
using defaults.
(brak wyspecyfikowanego pliku definicji .DEF; stosuję wartości
domyślne)
I tu już możemy coś zaradzić. Możemy zatem pokusić się o
stworzenie naszego pierwszego pliku definicji (nazwa jest trochę
myląca - chodzi o zdefiniowanie sposobu wykorzystania zasobów
środowiska Windows).
Aby utworzyć plik .DEF (jest to plik ASCII) należy:
1. Otworzyć nowe okienko edycyjne (nie wychodząc z IDE):
File | New
Otworzy się okienko NONAMExx.CPP. Ta nazwa nie jest oczywiście
najodpowiedniejsza, więc umieszczamy plik we właściwym katalogu
(tym samym, co główny program *.CPP) przy pomocy rozkazu File |
Save as...
i nadajemy plikowi stosowną nazwę i rozszerzenie *.DEF. Okieno
pozostaje puste, ma jednak "focus" i nową nazwę, np.
C:\..\PR.DEF.
3. Redagujemy nasz pierwszy plik definicji, np. tak:
NAME JAKAKOLWIEK // <-- nazwa aplikacji
DESCRIPTION 'Opis: A. MAJCZAK, BC C++ 3...4'
EXETYPE WINDOWS // <-- EXE dla Windows
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 4096 // <-- sterta 4 KB
STACKSIZE 5120 // <-- stos 5 KB
_______________________________________________________________
UWAGA:
W przypadku tworzenia bibliotek .DLL dane muszą mieć status
SINGLE (pojedyncze) zamiast MULTIPLE (wielokrotne). Użycie tu
słowa MULTIPLE pozwoli nam na wielokrotne uruchamianie
aplikacji.
________________________________________________________________
Możnaby tu zapytać - po co to robić, skoro używamy standardowych
wartości i obecność tego pliku nie wnosi nic nowego do sposobu
działania naszego programu?
Odpowiedź jest prosta. Mając taki plik będziemy mogli
prześledzić stadia tworzenia tzw. projektu (w BC++ 4 bez tego
ani rusz). Zapisujemy zatem plik na dysk:
4. File | Save. (plik .DEF zostaje zapisany na dysku).
Ponieważ pracujemy w środowisku Windows, okno edycji pliku *.DEF
możemy traktować podobnie jak każde inne okno. Najwygodniej
zatem przejść do okna edycji głównego pliku żródłowego *.CPP
przy pomocy własnego menu systemowego tegoż okna.
5. Menu Systemowe [-] | Zamknij.
I możemy przystąpić do tworzenia projektu składającego się z dwu
plików: *.CPP i *.DEF. Jeśli, dla przykładu, przyjmiemy w tym
miejscu, że nasze dwa moduły nazywają się: WINZ2.CPP i WINZ2.DEF
i są przechowywane w katalogu głównym dysku C:\ , kolejność
czynności powinna być następująca:
1. Rozwijamy menu Project ([Alt]+[P] lub myszką).
2. Wybieramy z menu rozkaz Open Project... (Utwórz projekt).
Pojawia się okienko dialogowe Open Project File z domyślnym
rozszerzeniem *.PRJ (w BC 4+ - *.IDE).
3. Do okienka File Name:
wpisujemy nazwę pliku z opisem projektu: np. WINZ2.PRJ.
W dolnej części ekranu otwiera się okienko
Project: WINZ2
4. Wybieramy z menu Project rozkaz Add item... (dodaj element do
projektu). Pojawia się okienko dialogowe "Add to Project List"
(dodawanie do listy elementów projektu).
5. Do okienka File Name: wpisujemy nazwę głównego pliku
projektu: WINZ2.CPP (*.cpp jest domyślnym rozszerzeniem).
Plik możemy wybrać także z listy w okienku Files: .
6. Wybieramy w okienku dialogowym klawisz [+Add] (dodaj do
projektu).
7. Wpisujemy nazwę kolejnego pliku wchodzącego w skład projektu
(w tym przypadku WINZ2.DEF).
8. Wybieramy klawisz [+Add] w okienku.
UWAGA: Czynności 7) i 8) w przypadku bardziej złożonych
projektów będą powtarzane wielokrotnie.
9. Wybieramy klawisz [Done] w okienku (zrobione/gotowe).
Konfigurowanie projektu zostało zakończone.
10. Przy pomocy rozkazów Compile, Link, Make, Build all, Run
możemy teraz skompilować, skonsolidować i uruchomić nasz program
w postaci projektu. Ostrzeżenie Linkera zniknie.
[!!!]UWAGA
________________________________________________________________
W dolnej części ekranu w stadium tworzenia projektów ( i póżniej
po załadowaniu pliku projektu [Open Project] pojawi się lista
plików. Do trybu edycji pliku możesz przjść poprzez dwukrotne
klinięcie pliku na tej liście.
Zwróć uwagę, że pliki projektów .PRJ ( w Borland 4+ .IDE)
przechowują również informacje o konfiguracji. Najważniejsza z
nich to informacja o katalogach, z których korzysta kompilator:
Options | Directories... | Include
Options | Directories... | Library
Options | Directories... | Output
________________________________________________________________
Najwygodniej przechowywać wszystkie pliki wchodzące w skład
jednego projektu w odrębnym katalogu dyskowym. Dla wprawy załóż
odrębny katalog i zapisz tam pliki:
*.CPP
*.DEF
*.PRJ (lub *.IDE)
dla swoich pierwszych dwóch projektów, które właśnie powstały.
[!!!] UWAGA
________________________________________________________________
Ten sam plik definicji możesz wykorzystywać do tworzenia
następnych przykładowych aplikacji typu Windows EXE.
________________________________________________________________