Rozdział XII - Pamięć i pliki


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}.

 

Teoria

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:

  1. Przydziel blok pamięci wywołując funkcję GlobalAlloc. Funkcja ta zwraca uchwyt do zażądanego bloku pamięci.
  2. Zabezpiecz blok pamięci wywołując GlobalLock. Funkcja ta przyjmuje jako parametr uchwyt do wcześniej przydzielonego bloku pamięci i zwraca wskazanie do tego bloku.
  3. Otrzymane wskazanie możesz wykorzystać do odczytu i zapisu przydzielonej pamięci.
  4. Odbezpiecz blok pamięci wywołując GlobalUnlock. Funkcja ta unieważnia wskazanie do bloku pamięci.
  5. Zwolnij blok pamięci wywołując GlobalFree. Funkcja ta akceptuje uchwyt bloku 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ć:

  1. Otwórz lub Utwórz plik przez wywołanie funkcji CreateFile. Funkcja ta jest bardzo wszechstronna: oprócz plików potrafi otwierać porty komunikacyjne, stacje dysków lub konsolę. Jeśli wywołanie się powiedzie, to zwraca ona uchwyt do pliku lub urządzenia. Możesz następnie użyć tego uchwytu do wykonywania operacji na tym pliku lub urządzeniu.
    Punkt odczytu/zapisu w pliku możesz przemieszczać wywołując SetFilePointer.
  2. Wykonaj operacje odczytu lub zapisu przy pomocy funkcji ReadFile lub WriteFile. Funkcje te przesyłają dane z bloku pamięci do pliku lub odwrotnie. Zatem musisz zarezerwować odpowiednio duży blok pamięci, aby pomieścił twoje dane.
  3. Zamknij plik wywołując funkcję CloseHandle. Funkcja ta akceptuje uchwyt pliku.

Treść

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
    }
}

Analiza

    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.

Dodatek w Pascalu

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.
Tłumaczenie z języka angielskiego, opracowanie HTML i konwersję przykładów programów wykonał mgr Jerzy Wałaszek.



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.