![]() |
Wyjście Spis treści Poprzedni Następny
Autor:
©Iczelion |
©2008 mgr
Jerzy Wałaszek
|
Na tej lekcji poznamy zasady zarządzania pamięcią oraz operacje wejścia/wyjścia na plikach. Dodatkowo zastosujemy typowe okienka dialogowe w charakterze elementów wprowadzania i wyprowadzania informacji.

Pobierz plik z przykładem {z tego archiwum}.
Z punktu widzenia aplikacji zarządzanie pamięcią w bibliotece Win32 jest całkiem proste. Każdy proces posiada przestrzeń adresową o rozmiarze 4GB. Używany jest płaski model pamięci (flat memory model). W modelu tym wszystkie rejestry segmentowe (selektory) wskazują na ten sam adres początkowy, a przemieszczenie w obrębie segmentu jest 32 bitowe, zatem każda aplikacja ma dostęp do każdej komórki pamięci w swojej własnej przestrzeni adresowej bez konieczności wymiany selektorów. Znacznie upraszcza to zarządzanie pamięcią. Nie ma już "bliskich" i "dalekich" wskazań.
W systemie Windows 16 bitowym istnieją dwie główne kategorie funkcji API zawiązanych z obsługą pamięci. Globalne i Lokalne. Wywołania API typu globalnego zajmują się obszarami pamięci przydzielonej w innych segmentach, zatem są to funkcje "dalekiej" pamięci (far memory). Wywołania API typu lokalnego zajmują się lokalnym stosem danego procesu, zatem są to funkcje "bliskiej" pamięci (near memory). W systemie 32 bitowym Windows oba te typy są identyczne. Czy wywołasz GlobalAlloc, czy LocalAlloc, zawsze otrzymasz ten sam wynik.
Oto niezbędne kroki przy przydzielaniu i korzystaniu z pamięci:
Możesz również zamienić "Global" przez "Local", np. jako LocalAlloc, LocalLock, itp.
Powyższa metoda może być dalej uproszczona przez zastosowanie znacznika GMEM_FIXED w wywołaniu GlobalAlloc. Jeśli użyjesz tego znacznika, to wartością zwrotną z Global/LocalAlloc będzie wskazanie przydzielonego bloku pamięci, a nie uchwyt do tego bloku. Nie musisz wtedy wywoływać Global/LocalLock i możesz przekazać to wskazanie do Global/LocalFree bez wcześniejszego wywoływania Global/LocalUnlock. Lecz w tym kursie użyję "tradycyjnego" podejścia, ponieważ możesz się z nim spotkać studiując kod źródłowy innych programów.
Operacje wejścia/wyjścia na plikach w bibliotece Win32 noszą znaczne podobieństwo do operacji w systemie DOS. Wymagane kroki są takie same. Musisz jedynie zastąpić przerwania wywołaniami funkcji API i gotowe (o ile orientujesz się w temacie!). Oto co należy wykonać:
Przedstawiony poniżej program wyświetla okno dialogowe otwierania pliku. Pozwala ono użytkownikowi na wybranie pliku tekstowego do otwarcia, a następnie zawartość tego pliku pojawi się w kontrolce edycyjnej na obszarze roboczym. Użytkownik może dowolnie modyfikować tekst w kontrolce edycyjnej, a następnie wybrać opcję zapisu zawartości do pliku.
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD
INCLUDE \masm32\include\windows.inc
INCLUDE \masm32\include\user32.inc
INCLUDE \masm32\include\kernel32.inc
INCLUDE \masm32\include\comdlg32.inc
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDELIB \masm32\lib\comdlg32.lib
.CONST
IDM_OPEN EQU 1
IDM_SAVE EQU 2
IDM_EXIT EQU 3
MAXSIZE EQU 260
MEMSIZE EQU 65535
EditID EQU 1
.DATA
ClassName DB "Win32ASMEditClass",0
AppName DB "Edytor w asemblerze Win32",0
EditClass DB "edit",0
MenuName DB "FirstMenu",0
ofn OPENFILENAME <>
FilterString DB "Wszystkie pliki (*.*)",0,"*.*",0
DB "Pliki tekstowe (*.txt)",0,"*.txt",0,0
buffer DB MAXSIZE DUP(0)
.DATA?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndEdit HWND ?
hFile HANDLE ?
hMemory HANDLE ?
pMemory DWORD ?
SizeReadWrite DWORD ?
.CODE
start:
INVOKE GetModuleHandle, NULL
mov hInstance, eax
INVOKE GetCommandLine
mov CommandLine, eax
INVOKE WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
INVOKE ExitProcess, eax
WinMain PROC hInst: HINSTANCE,\
hPrevInst: HINSTANCE,\
CmdLine: LPSTR,\
CmdShow: DWORD
LOCAL wc: WNDCLASSEX
LOCAL msg: MSG
LOCAL hwnd: HWND
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW OR CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground, COLOR_WINDOW+1
mov wc.lpszMenuName, OFFSET MenuName
mov wc.lpszClassName, OFFSET ClassName
INVOKE LoadIcon, NULL, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
INVOKE LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax
INVOKE RegisterClassEx, ADDR wc
INVOKE CreateWindowEx, WS_EX_CLIENTEDGE,\
ADDR ClassName, ADDR AppName,\
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,\
CW_USEDEFAULT, 300, 200, NULL, NULL,\
hInst, NULL
mov hwnd, eax
INVOKE ShowWindow, hwnd, SW_SHOWNORMAL
INVOKE UpdateWindow, hwnd
.WHILE TRUE
INVOKE GetMessage, ADDR msg, NULL, 0, 0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax, msg.wParam
ret
WinMain ENDP
WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_CREATE
INVOKE CreateWindowEx, NULL, ADDR EditClass, NULL,\
WS_VISIBLE OR \
WS_CHILD OR \
ES_LEFT OR \
ES_MULTILINE OR \
ES_AUTOHSCROLL OR \
ES_AUTOVSCROLL,\
0, 0, 0, 0, hWnd, EditID,\
hInstance, NULL
mov hwndEdit, eax
INVOKE SetFocus, hwndEdit
mov ofn.lStructSize, SIZEOF ofn
push hWnd
pop ofn.hWndOwner
push hInstance
pop ofn.hInstance
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile, MAXSIZE
.ELSEIF uMsg==WM_SIZE
xor eax, eax
mov ax, WORD PTR lParam
xor edx, edx
mov dx, WORD PTR lParam + 2
INVOKE MoveWindow, hwndEdit, 0, 0, eax, edx, TRUE
.ELSEIF uMsg==WM_DESTROY
INVOKE PostQuitMessage, NULL
.ELSEIF uMsg==WM_COMMAND
mov eax, wParam
.IF lParam==0
.IF ax==IDM_OPEN
mov ofn.Flags, OFN_FILEMUSTEXIST OR \
OFN_PATHMUSTEXIST OR \
OFN_LONGNAMES OR \
OFN_EXPLORER OR \
OFN_HIDEREADONLY
INVOKE GetOpenFileName, ADDR ofn
.IF eax==TRUE
INVOKE CreateFile, ADDR buffer,\
GENERIC_READ OR GENERIC_WRITE ,\
FILE_SHARE_READ OR FILE_SHARE_WRITE,\
NULL, OPEN_EXISTING,\
FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile, eax
INVOKE GlobalAlloc, GMEM_MOVEABLE OR GMEM_ZEROINIT,\
MEMSIZE
mov hMemory, eax
INVOKE GlobalLock, hMemory
mov pMemory, eax
INVOKE ReadFile, hFile, pMemory, MEMSIZE-1,\
ADDR SizeReadWrite, NULL
INVOKE SendMessage, hwndEdit, WM_SETTEXT,\
NULL, pMemory
INVOKE CloseHandle, hFile
INVOKE GlobalUnlock, pMemory
INVOKE GlobalFree, hMemory
.ENDIF
INVOKE SetFocus, hwndEdit
.ELSEIF ax==IDM_SAVE
mov ofn.Flags, OFN_LONGNAMES OR \
OFN_EXPLORER OR OFN_HIDEREADONLY
INVOKE GetSaveFileName, ADDR ofn
.IF eax==TRUE
INVOKE CreateFile, ADDR buffer,\
GENERIC_READ OR GENERIC_WRITE,\
FILE_SHARE_READ OR FILE_SHARE_WRITE,\
NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE,\
NULL
mov hFile, eax
INVOKE GlobalAlloc, GMEM_MOVEABLE OR GMEM_ZEROINIT,\
MEMSIZE
mov hMemory, eax
INVOKE GlobalLock, hMemory
mov pMemory, eax
INVOKE SendMessage, hwndEdit, WM_GETTEXT,\
MEMSIZE-1, pMemory
INVOKE WriteFile, hFile, pMemory, eax,\
ADDR SizeReadWrite, NULL
INVOKE CloseHandle, hFile
INVOKE GlobalUnlock, pMemory
INVOKE GlobalFree, hMemory
.ENDIF
INVOKE SetFocus, hwndEdit
.ELSE
INVOKE DestroyWindow, hWnd
.ENDIF
.ENDIF
.ELSE
INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.ENDIF
xor eax, eax
ret
WndProc ENDP
END start
Plik zasobów FILE.RC
// Stałe dla menu
#define IDM_OPEN 1
#define IDM_SAVE 2
#define IDM_EXIT 3
FirstMenu MENU
{
POPUP "&Plik"
{
MENUITEM "&Otwórz...", IDM_OPEN
MENUITEM "&Zapisz jako...", IDM_SAVE
MENUITEM SEPARATOR
MENUITEM "&Koniec", IDM_EXIT
}
}
INVOKE CreateWindowEx, NULL, ADDR EditClass, NULL,\
WS_VISIBLE OR \
WS_CHILD OR \
ES_LEFT OR \
ES_MULTILINE OR \
ES_AUTOHSCROLL OR \
ES_AUTOVSCROLL,\
0, 0, 0, 0, hWnd, EditID,\
hInstance, NULL
mov hwndEdit, eax
W sekcji WM_CREATE tworzymy kontrolkę
edycyjną. Zwróć uwagę, iż parametry określające położenie x
i y oraz szerokość i wysokość kontrolki są wszystkie
ustawione na zero, ponieważ za chwilę zmienimy rozmiar tej kontrolki, tak aby pokrywała cały obszar roboczy okna nadrzędnego.
Zauważ, iż w tym przypadku nie musimy wywoływać funkcji ShowWindow, aby kontrolka edycyjna pojawiła się na ekranie, ponieważ dołączyliśmy styl WS_VISIBLE. Sztuczkę tę możesz również zastosować w oknie nadrzędnym.
Inicjujemy pola struktury OPENFILE.
mov ofn.lStructSize, SIZEOF ofn
push hWnd
pop ofn.hWndOwner
push hInstance
pop ofn.hInstance
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile, MAXSIZE
Po utworzeniu kontrolki edycyjnej zabieramy się do inicjalizacji pól struktury
ofn. Ponieważ chcemy z niej również korzystać w oknie dialogowym
"Zapisywanie jako...", wypełnimy jedynie wspólne pola, które są używane przez
oba okna dialogowe GetOpenFileName
i GetSaveFileName.
Sekcja WM_CREATE jest bardzo dobrym miejscem na wykonanie początkowych inicjalizacji, których później już nie powtarzamy.
.ELSEIF uMsg==WM_SIZE
xor eax, eax
mov ax, WORD PTR lParam
xor edx, edx
mov dx, WORD PTR lParam + 2
INVOKE MoveWindow, hwndEdit, 0, 0, eax, edx, TRUE
Wiadomości WM_SIZE otrzymujemy, gdy zmienia się rozmiar
obszaru roboczego naszego głównego okna. Wiadomości te docierają do nas również
w przypadku, gdy okno jest tworzone po raz pierwszy. Aby otrzymywać tę
wiadomość, style klasy okna muszą zawierać
CS_VREDRAW oraz CS_HREDRAW.
Wykorzystamy tę okazję do powiększenia naszej kontrolki edycyjnej na cały obszar
roboczy okna nadrzędnego. Najpierw musimy poznać bieżące wymiary tego obszaru.
Informację tę odczytamy z lParam. Starsze słowo
lParam zawiera wysokość a młodsze słowo zawiera szerokość obszaru
roboczego. Następnie używamy tę informację do zmiany rozmiaru kontrolki
edycyjnej przez wywołanie funkcji
MoveWindow, która oprócz zmiany pozycji okna
potrafi również zmodyfikować jego wymiary.
.IF ax==IDM_OPEN
mov ofn.Flags, OFN_FILEMUSTEXIST OR \
OFN_PATHMUSTEXIST OR \
OFN_LONGNAMES OR \
OFN_EXPLORER OR \
OFN_HIDEREADONLY
INVOKE GetOpenFileName, ADDR ofn
Gdy użytkownik wybierze z menu opcję Plik/Otwórz,
wypełniamy pole Flags struktury
ofn i wywołujemy funkcję
GetOpenFileName, aby wyświetlić okno dialogowe otwierania pliku.
.IF eax==TRUE
INVOKE CreateFile, ADDR buffer,\
GENERIC_READ OR GENERIC_WRITE ,\
FILE_SHARE_READ OR FILE_SHARE_WRITE,\
NULL, OPEN_EXISTING,\
FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile, eax
Po wybraniu pliku do otwarcia wywołujemy funkcję CreateFile,
która otworzy ten plik. W wywołaniu określamy, iż funkcja powinna spróbować
otworzyć plik do zapisu i odczytu. Po otwarciu pliku funkcja zwraca uchwyt do
niego, który zapamiętujemy w globalnej zmiennej dla przyszłych zastosowań.
Funkcja ta posiada następującą składnię:
CreateFile PROTO lpFileName: DWORD,\
dwDesiredAccess: DWORD,\
dwShareMode: DWORD,\
lpSecurityAttributes: DWORD,\
dwCreationDistribution: DWORD,\
dwFlagsAndAttributes: DWORD,\
hTemplateFile: DWORD INVOKE GlobalAlloc, GMEM_MOVEABLE OR GMEM_ZEROINIT,\
MEMSIZE
mov hMemory, eax
INVOKE GlobalLock, hMemory
mov pMemory, eax
Po otwarciu pliku rezerwujemy blok pamięci do dyspozycji funkcji
ReadFile i WriteFile.
Określamy znacznik GMEM_MOVEABLE, aby pozwolić systemowi
Windows przemieszczać ten blok w pamięci przy jej konsolidacji. Znacznik
GMEM_ZEROINIT nakazuje funkcji
GlobalAlloc wypełnienie zerami nowo przydzielonego
bloku pamięci.
Gdy funkcja GlobalAlloc powróci z sukcesem, rejestr eax zawiera uchwyt przydzielonego bloku pamięci. Uchwyt ten przekazujemy do funkcji GlobalLock function, która zwróci wskazanie do bloku pamięci. Jednocześnie pozycja bloku zostaje zamrożona w obszarze pamięci - Windows nie będzie go przesuwał.
INVOKE ReadFile, hFile, pMemory, MEMSIZE-1,\
ADDR SizeReadWrite, NULL
INVOKE SendMessage, hwndEdit, WM_SETTEXT,\
NULL, pMemory
Gdy blok pamięci jest gotowy do użytku, wywołujemy funkcję ReadFile, aby odczytać dane z pliku. Przy pierwszym otwarciu lub utworzeniu pliku wskaźnik pozycji w pliku ustawiony jest na 0. Zatem w tym przypadku rozpoczynamy odczyt od pierwszego bajtu w pliku. Pierwszym parametrem funkcji ReadFile jest uchwyt pliku do odczytu, drugi jest wskazaniem bloku pamięci do przechowania danych, następny określa liczbę bajtów do odczytu z pliku, czwarty jest wskazaniem zmiennej typu DWORD, do której funkcja zapisze liczbę faktycznie odczytanych z pliku bajtów, a z piątego parametru tutaj nie korzystamy (skonsultuj się z plikami pomocy dla Win32).
Po wypełnieniu bloku pamięci danymi wstawiamy je do kontrolki edycyjnej wysyłając do niej wiadomość WM_SETTEXT z lParam zawierającym wskazanie bloku pamięci. Po tym wywołaniu, kontrolka edycyjna pokaże dane na swoim obszarze roboczym.
INVOKE CloseHandle, hFile
INVOKE GlobalUnlock, pMemory
INVOKE GlobalFree, hMemory
.ENDIF
W tym momencie nie musimy już utrzymywać pliku otwartym, ponieważ naszym
celem jest zapis zmodyfikowanych w kontrolce edycyjnej danych w innym
pliku, a nie w pierwotnym. Zatem zamykamy ten plik wywołując
CloseHandle z uchwytem do pliku jako parametrem.
Następnie odblokowujemy pamięć i zwalniamy ją. Właściwie nie musisz
tutaj zwalniać tej pamięci, mógłbyś ponownie wykorzystać ją później przy
operacji zapisu. Lecz dla celów demonstracyjnych zdecydowałem się ją
zwolnić.
INVOKE SetFocus, hwndEdit
Gdy okienko dialogowe otwierania pliku zostaje wyświetlona na ekranie, staje się
aktywne (przejmuje ognisko wejścia danych - input focus).
Zatem po jego zamknięciu musimy z powrotem uaktywnić kontrolkę edycyjną.
Kończy to operację odczytu na tym pliku. W tym momencie użytkownik może modyfikować zawartość kontrolki edycyjnej. A gdy zechce zapisać te dane do innego pliku, musi wybrać z menu opcję Plik/Zapisz Jako, która wyświetli okienko dialogowe zapisu pliku. Tworzenie okna dialogowego zapisu pliku nie różni się zasadniczo od tworzenia okienka dialogowego otwierania pliku. Właściwie różnią się one tylko nazwą wywoływanej funkcji API - GetOpenFileName i GetSaveFileName. Można ponownie wykorzystać większość pól struktury ofn, za wyjątkiem pola Flags.
mov ofn.Flags, OFN_LONGNAMES OR \
OFN_EXPLORER OR OFN_HIDEREADONLY
INVOKE GetSaveFileName, ADDR ofn
W naszym przypadku chcemy utworzyć nowy plik, zatem musimy porzucić znaczniki
OFN_FILEMUSTEXIST oraz
OFN_PATHMUSTEXIST, inaczej okno dialogowe nie
pozwoli nam utworzyć pliku, który jeszcze nie istnieje.
Parametr dwCreationDistribution funkcji CreateFile musi się zmienić na CREATE_NEW, ponieważ chcemy utworzyć nowy plik. Pozostały kod jest identyczny z sekcją otwierania pliku, za wyjątkiem następującego fragmentu:
INVOKE SendMessage, hwndEdit, WM_GETTEXT,\
MEMSIZE-1, pMemory
INVOKE WriteFile, hFile, pMemory, eax,\
ADDR SizeReadWrite, NULL
Wysyłamy wiadomość WM_GETTEXT do kontrolki edycyjnej, aby
skopiować dane z niej do dostarczonego przez nas bloku pamięci, a wartością
zwrotną w rejestrze eax
jest długość danych wewnątrz bufora. Po wprowadzeniu danych do bloku
pamięci, zapisujemy go do nowego pliku.
Ta sama aplikacja w Pascalu:
{********************************
** I Liceum Ogólnokształcące **
** w Tarnowie **
** mgr Jerzy Wałaszek **
********************************}
program MemFile;
uses windows;
const
IDM_OPEN = 1;
IDM_SAVE = 2;
IDM_EXIT = 3;
MAXSIZE = 260;
MEMSIZE = 65535;
EditID = 1;
ClassName = 'Win32ASMEditClass';
AppName = 'Edytor w FreePascalu';
EditClass = 'edit';
MenuName = 'FirstMenu';
FilterString = 'Wszystkie pliki (*.*)'#0'*.*'#0'Pliki tekstowe (*.txt)'#0'*.txt'#0#0;
var
ofn : OPENFILENAME;
buffer : array[0..MAXSIZE] of char;
hInstance : HINST;
hwndEdit : HWND;
function WndProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM) : integer;
var
hFile : HANDLE;
hMemory : HANDLE;
pMemory : POINTER;
SizeReadWrite : longint;
begin
WndProc := 0;
case uMsg of
WM_CREATE : begin
hwndEdit := CreateWindowEx(0,EditClass,0,
WS_VISIBLE or WS_CHILD or
ES_LEFT or ES_MULTILINE or
ES_AUTOHSCROLL or ES_AUTOVSCROLL,
0,0,0,0,hWnd,EditID,hInstance,0);
SetFocus(hwndEdit);
ofn.lStructSize := sizeof(ofn);
ofn.hWndOwner := hWnd;
ofn.hInstance := hInstance;
ofn.lpstrFilter := FilterString;
ofn.lpstrFile := @buffer;
ofn.nMaxFile := MAXSIZE;
end;
WM_SIZE : MoveWindow(hwndEdit,0,0,lParam and $ffff,lParam shr 16,true);
WM_DESTROY: PostQuitMessage(0);
WM_COMMAND: if lParam = 0 then
case (wParam and $ffff) of
IDM_OPEN : begin
ofn.Flags := OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or
OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY;
if GetOpenFileName(@ofn) then
begin
hFile := CreateFile(@buffer,GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
0,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,0);
hMemory := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE);
pMemory := GlobalLock(hMemory);
ReadFile(hFile,pMemory^,MEMSIZE-1,SizeReadWrite,0);
SendMessage(hwndEdit,WM_SETTEXT,0,longint(pMemory));
CloseHandle(hFile);
GlobalUnlock(longint(pMemory));
GlobalFree(hMemory);
end;
SetFocus(hwndEdit);
end;
IDM_SAVE : begin
ofn.Flags := OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY;
if GetSaveFileName(@ofn) then
begin
hFile := CreateFile(@buffer, GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
0, CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,0);
hMemory := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE);
pMemory := GlobalLock(hMemory);
WriteFile(hFile,pMemory^,
SendMessage(hwndEdit,WM_GETTEXT,MEMSIZE-1, longint(pMemory)),
SizeReadWrite,0);
CloseHandle(hFile);
GlobalUnlock(longint(pMemory));
GlobalFree(hMemory);
end;
SetFocus(hwndEdit);
end;
else DestroyWindow(hWnd);
end;
else WndProc := DefWindowProc(hWnd,uMsg,wParam,lParam);
end;
end;
function WinMain(hInst,hPrevInst:HINST;CmdLine:LPSTR;CmdShow:DWORD): longint;
var
wc : WNDCLASSEX;
msg : MSG;
hwnd : HWND;
begin
wc.cbSize := sizeof(WNDCLASSEX);
wc.style := CS_HREDRAW or CS_VREDRAW;
wc.lpfnWndProc := @WndProc;
wc.cbClsExtra := 0;
wc.cbWndExtra := 0;
wc.hInstance := hInst;
wc.hbrBackground := COLOR_WINDOW + 1;
wc.lpszMenuName := MenuName;
wc.lpszClassName := ClassName;
wc.hIcon := LoadIcon(0,IDI_APPLICATION);
wc.hIconSm := wc.hIcon;
wc.hCursor := LoadCursor(0,IDC_ARROW);
RegisterClassEx(wc);
hwnd := CreateWindowEx(WS_EX_CLIENTEDGE,ClassName,AppName,
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
300,200,0,0,hInst,0);
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
while GetMessage(msg,0,0,0) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
WinMain := msg.wParam;
end;
begin
hInstance := GetModuleHandle(0);
ExitProcess(WinMain(hInstance,0,GetCommandLine,SW_SHOWDEFAULT));
end.
|
Autorem
kursu jest
Iczelion. Kurs
programowania Windows znalazł się na serwerze I LO w Tarnowie za pisemną
zgodą autora. |
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe