Rozdział XI - Więcej o oknie dialogowym


Na tej lekcji nauczymy się nowych rzeczy na temat okien dialogowych. W szczególności przerobimy temat używania okien dialogowych w formie narzędzi wprowadzania i wyprowadzania informacji w naszych programach. Jeśli przestudiowałeś lekcję poprzednią, to ta będzie dla ciebie jak bułka z masłem, ponieważ wymagane są tylko kosmetyczne zmiany w kodzie, aby móc używać okna dialogowe jako dodatki do naszego okna głównego. Również lekcja ta obejmie stosowanie typowych okien dialogowych.


obrazek


Pobierz przykłady okien dialogowych {z tego archiwum} oraz {z tego archiwum}. Pobierz przykład Typowych Okien Dialogowych {z tego archiwum}.


Teoria

O użyciu okien dialogowych w charakterze narzędzi wprowadzania i wyprowadzania informacji nie musimy już wiele mówić. Twój program tworzy główne okno w zwykły sposób, a gdy chcesz wyświetlić okno dialogowe, po prostu wywołujesz funkcję CreateDialogParam lub DialogBoxParam. Przy wywołaniu DialogBoxParam nie musisz już nic więcej robić, tylko wystarczy obsługiwać wiadomości w procedurze okna dialogowego. Przy CreateDialogParam musisz wstawić do pętli wiadomości wywołanie IsDialogMessage w celu umożliwienia zarządcy okna dialogowego obsługi nawigacji z klawiatury wśród kontrolek na twoim oknie dialogowym.

Plik DIALOG.ASM wersja z CreateDialogParam

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

INCLUDE    \masm32\INCLUDE\windows.inc
INCLUDE    \masm32\INCLUDE\user32.inc
INCLUDE    \masm32\INCLUDE\kernel32.inc
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib

WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD
DlgProc PROTO :HWND,  :DWORD, :DWORD, :DWORD

.DATA

ClassName  DB "SimpleWinClass", 0
AppName    DB "Nasze okno główne", 0
MenuName   DB "FirstMenu", 0
DlgName    DB "MyDialog", 0
TestString DB "Cześć wszystkim", 0
hwndDlg    DD 0                   ; Uchwyt do okna dialogowego

.DATA?

hInstance   HINSTANCE ?
CommandLine LPSTR     ?

.CONST

IDM_EXIT   EQU    1
IDM_ABOUT  EQU    2
IDC_EDIT   EQU 3000
IDC_BUTTON EQU 3001
IDC_EXIT   EQU 3002

.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)
        .IF hwndDlg!=0
            INVOKE IsDialogMessage, hwndDlg, ADDR msg
            .IF eax==TRUE
                .CONTINUE
            .ENDIF
        .ENDIF
        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_DESTROY
        INVOKE PostQuitMessage, NULL
    .ELSEIF uMsg==WM_COMMAND
        .IF WORD PTR wParam==IDM_ABOUT
            INVOKE CreateDialogParam, hInstance,\
                                      ADDR DlgName, hWnd,\
                                      OFFSET DlgProc, NULL
            mov hwndDlg, eax
        .ELSE
            INVOKE DestroyWindow, hWnd
        .ENDIF
    .ELSE
        INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF

    xor eax, eax
    ret

WndProc ENDP

DlgProc PROC hWnd:HWND, iMsg:DWORD, wParam:WPARAM, lParam:LPARAM

    .IF iMsg==WM_INITDIALOG
        INVOKE GetDlgItem, hWnd, IDC_EDIT
        INVOKE SetFocus, eax
    .ELSEIF iMsg==WM_CLOSE
        INVOKE EndDialog, hWnd, NULL
        mov hwndDlg, 0
    .ELSEIF iMsg==WM_COMMAND
        mov ax, WORD PTR wParam
        .IF WORD PTR wParam+2==BN_CLICKED
            .IF ax==IDC_EXIT
                INVOKE SendMessage, hWnd, WM_CLOSE, NULL, NULL
            .ELSEIF ax==IDC_BUTTON
                INVOKE SetDlgItemText, hWnd, IDC_EDIT, ADDR TestString
            .ENDIF
        .ENDIF		   
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF
    mov  eax, TRUE
    ret

DlgProc ENDP

END start

 

Plik DIALOG.RC

 

// stałe dla okna dialogowego

#define IDC_EDIT            3000
#define IDC_BUTTON          3001
#define IDC_EXIT            3002
#define DS_CENTER           0x0800L
#define DS_CENTER           0x0800L
#define WS_MINIMIZEBOX      0x00020000L
#define WS_SYSMENU          0x00080000L
#define WS_VISIBLE          0x10000000L
#define WS_OVERLAPPED       0x00000000L
#define DS_MODALFRAME       0x80L
#define DS_3DLOOK           0x0004L
#define WS_CAPTION          0xC00000L
#define ES_AUTOHSCROLL      0x80L
#define ES_LEFT             0

// stałe dla menu

#define IDM_EXIT 1
#define IDM_ABOUT 2

FirstMenu MENU
{
    POPUP "&Plik"
    {
        MENUITEM "&Koniec", IDM_EXIT
    }
    MENUITEM "O programie", IDM_ABOUT
}


MyDialog DIALOG 10, 10, 205, 60

STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
      WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME |
      DS_3DLOOK

CAPTION "Nasze drugie okno dialogowe"
{
    EDITTEXT         IDC_EDIT, 15, 17, 111, 13, ES_AUTOHSCROLL | ES_LEFT
    DEFPUSHBUTTON   "Cześć", IDC_BUTTON, 141, 10, 52, 13
    PUSHBUTTON      "&Koniec", IDC_EXIT, 141, 26, 52, 13
}

 

Plik DIALOG.ASM wersja z DialogBoxParam

 

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

INCLUDE    \masm32\include\windows.inc
INCLUDE    \masm32\include\user32.inc
INCLUDE    \masm32\include\kernel32.inc
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib

WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD
DlgProc PROTO :HWND,  :DWORD, :DWORD, :DWORD

.DATA

ClassName  DB "SimpleWinClass",0
AppName    DB "Nasze okno główne",0
MenuName   DB "FirstMenu",0
DlgName    DB "MyDialog",0
TestString DB "Cześć wszystkim",0

.DATA?

hInstance   HINSTANCE ?
CommandLine LPSTR     ?

.CONST

IDM_EXIT   EQU    1
IDM_ABOUT  EQU    2
IDC_EDIT   EQU 3000
IDC_BUTTON EQU 3001
IDC_EXIT   EQU 3002

.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_DESTROY
        INVOKE PostQuitMessage, NULL
    .ELSEIF uMsg==WM_COMMAND
        .IF WORD PTR wParam==IDM_ABOUT
            INVOKE DialogBoxParam, hInstance,\
                                   ADDR DlgName, hWnd,\
                                   OFFSET DlgProc, NULL
        .ELSE
            INVOKE DestroyWindow, hWnd
        .ENDIF
    .ELSE
        INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF
	
    xor eax, eax
    ret
    
WndProc ENDP

DlgProc PROC hWnd:HWND, iMsg:DWORD, wParam:WPARAM, lParam:LPARAM

    .IF iMsg==WM_INITDIALOG
        INVOKE GetDlgItem, hWnd, IDC_EDIT
        INVOKE SetFocus, eax
    .ELSEIF iMsg==WM_CLOSE
        INVOKE EndDialog, hWnd, NULL
    .ELSEIF iMsg==WM_COMMAND
        mov ax, WORD PTR wParam
        .IF WORD PTR wParam+2==BN_CLICKED
            .IF ax==IDC_EXIT
                INVOKE SendMessage, hWnd, WM_CLOSE, NULL, NULL
            .ELSEIF ax==IDC_BUTTON
                INVOKE SetDlgItemText, hWnd, IDC_EDIT, ADDR TestString
            .ENDIF
        .ENDIF
    .ELSE
        mov eax, FALSE
        ret
    .ENDIF

    mov  eax, TRUE
    ret

DlgProc ENDP

END start

 

Przejdźmy do typowych okien dialogowych. System Windows przygotował predefiniowane okna dialogowe do użytku przez twoje aplikacje. Istnieją one w celu zapewnienia standartowego interfejsu użytkownika. Składają się z okienek dialogowych pliku, drukowania, koloru, czcionki i wyszukiwania. Powinieneś z nich zawsze korzystać. Zawarte są one w bibliotece comdlg32.dll. Aby ich użyć, musisz dołączyć do swojej aplikacji bibliotekę exportu comdlg32.lib. Tworzysz te okna dialogowe poprzez wywołanie odpowiednich funkcji z biblioteki. Dla okienka dialogowego otwarcia pliku będzie to funkcja GetOpenFileName, dla okienka dialogowego zapisu jest to GetSaveFileName, okienko dialogowe wydruku to PrintDlg i tak dalej. Każda z tych funkcji przyjmuje jako parametr wskazanie pewnej struktury, której dokładny opis znajdziesz w plikach pomocy dla API biblioteki Win32. Na tej lekcji zademonstruję, jak utworzyć i zastosować okno dialogowe odczytu pliku z dysku.


obrazek


Poniżej mamy prototyp funkcji GetOpenFileName:


GetOpenFileName PROTO lpofn:DWORD


Jak widać funkcja ta otrzymuje tylko jeden parametr, wskazanie do struktury OPENFILENAME. Wartość zwrotna TRUE oznacza, iż użytkownik wybrał plik do otwarcia, a FALSE oznacza przypadek odwrotny. Przyjrzyjmy się następnie strukturze OPENFILENAME.


OPENFILENAME STRUCT 
    lStructSize       DWORD     ?
    hwndOwner         HWND      ?
    hInstance         HINSTANCE ?
    lpstrFilter       LPCSTR    ?
    lpstrCustomFilter LPSTR     ?
    nMaxCustFilter    DWORD     ?
    nFilterIndex      DWORD     ?
    lpstrFile         LPSTR     ?
    nMaxFile          DWORD     ?
    lpstrFileTitle    LPSTR     ?
    nMaxFileTitle     DWORD     ?
    lpstrInitialDir   LPCSTR    ?
    lpstrTitle        LPCSTR    ?
    Flags             DWORD     ?
    nFileOffset       WORD      ?
    nFileExtension    WORD      ?
    lpstrDefExt       LPCSTR    ?
    lCustData         LPARAM    ?
    lpfnHook          DWORD     ?
    lpTemplateName    LPCSTR    ?
OPENFILENAME ENDS


Zobaczmy na znaczenie często używanych pól tej struktury:

FilterString DB "Wszystkie pliki (*.*)", 0, "*.*", 0
             DB "Pliki tekstowe (*.txt)", 0,"*.txt", 0, 0 


Zauważ, iż tylko szablon w drugim tekście każdej pary jest w rzeczywistości wykorzystywany przez system Windows do filtrowania plików. Również zauważ, iż na końcu łańcuchów filtrów musisz dodać dodatkowe zero, aby zaznaczyć koniec tej listy filtrów.

Przykład

Poniższy program wyświetla okna dialogowe otwierania pliku, gdy użytkownik wybierze opcję menu Plik ® Otwórz. Gdy w oknie dialogowym użytkownik wybierze jakiś plik, program wyświetli okno wiadomości z pełną nazwą, nazwą oraz z rozszerzeniem wybranego pliku.

Plik OPEN.ASM

 

.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_EXIT   EQU   2
MAXSIZE    EQU 260
OUTPUTSIZE EQU 512

.DATA

ClassName  DB "SimpleWinClass",0
AppName    DB "Nasze okno główne",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)
OurTitle      DB "Okno dialogowe otwarcia pliku: wybierz plik",0
FullPathName  DB "Pełna nazwa pliku ze ścieżką to: ",0
FullName      DB "Nazwa pliku to: ",0
ExtensionName DB "Rozszerzenie nazwy to: ",0
OutputString  DB OUTPUTSIZE DUP(0)

CrLf          DB 0Dh,0Ah,0         ;znaki końca wiersza i powrotu karetki

.DATA?

hInstance   HINSTANCE ?
CommandLine LPSTR     ?

.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_DESTROY
        INVOKE PostQuitMessage, NULL
    .ELSEIF uMsg==WM_COMMAND
        mov eax, wParam
        .IF ax==IDM_OPEN
            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
            mov  ofn.Flags, OFN_FILEMUSTEXIST OR OFN_PATHMUSTEXIST OR \
                            OFN_LONGNAMES OR OFN_EXPLORER OR \
                            OFN_HIDEREADONLY
            mov  ofn.lpstrTitle, OFFSET OurTitle
            INVOKE GetOpenFileName, ADDR ofn
            .IF eax==TRUE
                INVOKE lstrcat, ADDR OutputString, ADDR FullPathName
                INVOKE lstrcat, ADDR OutputString, ofn.lpstrFile
                INVOKE lstrcat, ADDR OutputString, ADDR CrLf
                INVOKE lstrcat, ADDR OutputString, ADDR FullName
                mov    eax, ofn.lpstrFile
                xor    edx, edx
                mov    dx, ofn.nFileOffset
                add    eax, edx
                INVOKE lstrcat, ADDR OutputString, eax
                INVOKE lstrcat, ADDR OutputString, ADDR CrLf
                INVOKE lstrcat, ADDR OutputString, ADDR ExtensionName
                mov    eax, ofn.lpstrFile
                xor    edx, edx
                mov    dx, ofn.nFileExtension
                add    eax, edx
                INVOKE lstrcat, ADDR OutputString, eax
                INVOKE MessageBox, hWnd,\
                                   ADDR OutputString,\
                                   ADDR AppName, MB_OK
                INVOKE RtlZeroMemory, ADDR OutputString, OUTPUTSIZE
            .ENDIF
        .ELSE
            INVOKE DestroyWindow, hWnd
        .ENDIF
    .ELSE
        INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF
    xor eax, eax
    ret
   
WndProc ENDP

END start

 

Plik OPEN.RC

 

// Stałe dla menu

#define IDM_OPEN 1
#define IDM_EXIT 2

FirstMenu MENU
{
    POPUP "&Plik"
    {
        MENUITEM "&Otwórz",IDM_OPEN
        MENUITEM SEPARATOR
        MENUITEM "&Koniec",IDM_EXIT
    }
}

 

Analiza

    mov  ofn.lStructSize, SIZEOF ofn
    push hWnd
    pop  ofn.hWndOwner
    push hInstance
    pop  ofn.hInstance


Wypełniamy rutynowe pola struktury ofn.


    mov ofn.lpstrFilter, OFFSET FilterString


Zmienna FilterString jest filtrem nazw plików, który określamy w sposób następujący:


FilterString  DB "Wszystkie pliki (*.*)",0,"*.*",0
              DB "Pliki tekstowe (*.txt)",0,"*.txt",0,0


Zwróć uwagę, iż wszystkie cztery łańcuchy tekstowe kończą się zerem. Pierwszy tekst opisuje filtr zawarty w drugim tekście. Właściwe szablony to "*.*" oraz "*.txt". Nic nie stoi na przeszkodzie, aby tutaj określić dowolny szablon. Po ostatnim szablonie MUSIMY umieścić dodatkowe zero, aby oznaczyć koniec listy filtrów. Nie zapominaj o tej drobnostce, albo twoje okno dialogowe będzie się dziwnie zachowywało.


    mov  ofn.lpstrFile, OFFSET buffer
    mov  ofn.nMaxFile, MAXSIZE


Określamy, gdzie okno dialogowe ma umieścić nazwę pliku wybranego przez użytkownika. Zwróć uwagę, iż w polu nMaxFile musimy podać maksymalny rozmiar przeznaczonego na nazwę bufora. Później z bufora możemy wydobyć nazwę.


    mov ofn.Flags, OFN_FILEMUSTEXIST OR OFN_PATHMUSTEXIST OR \
                   OFN_LONGNAMES OR OFN_EXPLORER OR \
                   OFN_HIDEREADONLY


Znaczniki określają charakterystykę tego okna dialogowego.

Istnieje o wiele więcej znaczników, które możesz wykorzystać. Jak zwykle zaglądnij do plików pomocy dla API biblioteki Win32.


    mov ofn.lpstrTitle, OFFSET OurTitle


Określamy tytuł okna dialogowego.


    INVOKE GetOpenFileName, ADDR ofn


Wywołujemy funkcję GetOpenFileName przekazując wskazanie do struktury ofn jako parametr.

W tym momencie na ekranie zostaje wyświetlone okno dialogowe otwierania pliku. Funkcja nie zwróci sterowania dopóki użytkownik nie wybierze jakiegoś pliku do otwarcia, nie kliknie przycisku Anuluj lub nie zamknie tego okna dialogowego. W rejestrze eax zostanie zwrócona wartość TRUE, jeśli użytkownik wybierze jakiś plik do otwarcia. W przeciwnym przypadku rejestr eax będzie zawierał wartość FALSE.


    .IF eax==TRUE
        INVOKE lstrcat, ADDR OutputString, ADDR FullPathName
        INVOKE lstrcat, ADDR OutputString, ofn.lpstrFile
        INVOKE lstrcat, ADDR OutputString, ADDR CrLf
        INVOKE lstrcat, ADDR OutputString, ADDR FullName

W przypadku, gdy użytkownik dokona wyboru jakiegoś pliku do otwarcia, przygotowujemy tekst wyjściowy do wyświetlenia w okienku wiadomości. Rezerwujemy odpowiedni blok pamięci w zmiennej OutputString, a następnie stosujemy funkcję API lstrcat do połączenia ze sobą kilku tekstów. Aby teksty te znalazły się w osobnych wierszach, musimy każdy z nich rozdzielić parą znaków CR i LF.


        mov  eax, ofn.lpstrFile
        xor  edx, edx
        mov  dx,  ofn.nFileOffset
        add  eax, edx
        INVOKE lstrcat, ADDR OutputString, eax


Powyższe wiersze wymagają nieco wyjaśnienia. Pole nFileOffset zawiera indeks w buforze ofn.lpstrFile. Jednakże nie możemy ich po prostu dodać do siebie bezpośrednio, ponieważ nFileOffset ma rozmiar WORD (16 bitów), a lpstrFile jest wskazaniem o rozmiarze DWORD (32 bity). Dlatego pobieramy ten indeks do młodszego słowa rejestru edx i dodajemy do wartości lpstrFile.


        INVOKE MessageBox, hWnd, ADDR OutputString, ADDR AppName, MB_OK


Wyświetlamy tekst w oknie wiadomości.


        INVOKE RtlZeroMemory, ADDR OutputString, OUTPUTSIZE


Musimy wyczyścić bufor OutputString przed wstawieniem do niego nowego tekstu, więc stosujemy do tego celu funkcję RtlZeroMemory

Dodatek w Pascalu

Ta sama aplikacja w Pascalu. Program używa tego samego pliku zasobów, co wersja asemblerowa. Powinieneś go umieścić w katalogu projektu pod nazwą RSRC.RC.

Wersja z CreateDialogParam:

 

{********************************
**  I Liceum Ogólnokształcące  **
**           w Tarnowie        **
**       mgr Jerzy Wałaszek    **
********************************}

program MoreDialog1;

uses Windows;

const
  ClassName  = 'SimpleWinClass';
  AppName    = 'Nasze okno główne';
  MenuName   = 'FirstMenu';
  DlgName    = 'MyDialog';
  TestString = 'Cześć wszystkim';
  IDM_EXIT   =    1;
  IDM_ABOUT  =    2;
  IDC_EDIT   = 3000;
  IDC_BUTTON = 3001;
  IDC_EXIT   = 3002;

var
  hwnddlg   : HWND;           //uchwyt do okna dialogowego
  hInstance : HInst; //uchwyt egzemplarza aplikacji

function DlgProc(hWnd:HWND;iMsg:DWORD;wParam:WPARAM;lParam:LPARAM) : longint;
begin
  DlgProc := longint(true);
  case iMsg of
    WM_INITDIALOG : SetFocus(GetDlgItem(hWnd,IDC_EDIT));
    WM_CLOSE      : begin
                      EndDialog(hWnd,0);
                      hwndDlg := 0;
                    end;
    WM_COMMAND    : if (wParam shr 16) = BN_CLICKED then
                      case (wParam and $ffff) of
                        IDC_EXIT   : SendMessage(hWnd,WM_CLOSE,0,0);
                        IDC_BUTTON : SetDlgItemText(hWnd,IDC_EDIT,TestString);
                      end;
    else DlgProc := longint(false);
  end;
end;

function WndProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM) : longint;
begin
  WndProc := 0;
  case uMsg of
    WM_DESTROY: PostQuitMessage(0);
    WM_COMMAND: if (wParam and $ffff) = IDM_ABOUT then
                  hwndDlg := CreateDialogParam(hInstance,DlgName,hWnd,@DlgProc,0)
                else DestroyWindow(hWnd);
    else  WndProc := DefWindowProc(hWnd,uMsg,wParam,lParam);
  end;
end;

function WinMain(hInst,hPrevInst:HINST;CmdLine:LPSTR;CmdShow:longint) : 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
    if (hwndDlg <> 0) and IsDialogMessage(hwndDlg,msg) then continue;
    TranslateMessage(msg);
    DispatchMessage(msg);
  end;
  WinMain := msg.wParam;
end;

begin
  hInstance := GetModuleHandle(0);
  ExitProcess(WinMain(hInstance,0,GetCommandLine,SW_SHOWDEFAULT));
end.

 

Program z wspólnym oknem dialogowym otwarcia pliku. Plik zasobów z wersji asemblerowej proszę umieścić w katalogu projektowym pod nazwą RSRC.RC.

 

{********************************
**  I Liceum Ogólnokształcące  **
**           w Tarnowie        **
**       mgr Jerzy Wałaszek    **
********************************}

program OpenDialog;

uses Windows;

const
  IDM_OPEN      =   1;
  IDM_EXIT      =   2;
  MAXSIZE       = 260;
  OUTPUTSIZE    = 512;
  ClassName     = 'SimpleWinClass';
  AppName       = 'Nasze okno główne';
  MenuName      = 'FirstMenu';
  FilterString  = 'Wszystkie pliki (*.*)'#0'*.*'#0 +
                  'Pliki tekstowe (*.txt)'#0'*.txt'#0#0;
  OurTitle      = 'Okno dialogowe otwarcia pliku: wybierz plik';
  FullPathName  = 'Pełna nazwa pliku ze ścieżką to: ';
  FullName      = 'Nazwa pliku to: ';
  ExtensionName = 'Rozszerzenie nazwy to: ';
  CrLf          = #13#10#0;           //znaki końca wiersza i powrotu karetki

var
  ofn          : OPENFILENAME;
  buffer       : array[0..MAXSIZE] of char;
  OutputString : array[0..OUTPUTSIZE] of char;
  hInstance    : HINST;

function WndProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM) : longint;
begin
  WndProc := 0;
  case uMsg of
    WM_DESTROY : PostQuitMessage(0);
    WM_COMMAND : if (wParam and $ffff) = IDM_OPEN then
                 begin
                   ofn.lStructSize := sizeof(ofn);
                   ofn.hWndOwner   := hWnd;
                   ofn.hInstance   := hInstance;
                   ofn.lpstrFilter := FilterString;
                   ofn.lpstrFile   := @buffer;
                   ofn.nMaxFile    := MAXSIZE;
                   ofn.Flags       := OFN_FILEMUSTEXIST or
                                      OFN_PATHMUSTEXIST or
                                      OFN_LONGNAMES or
                                      OFN_EXPLORER or
                                      OFN_HIDEREADONLY;
                   ofn.lpstrTitle  := OurTitle;
                   if GetOpenFileName(@ofn) then
                   begin
                     lstrcat(@OutputString,FullPathName);
                     lstrcat(@OutputString,ofn.lpstrFile);
                     lstrcat(@OutputString,CrLf);
                     lstrcat(@OutputString,FullName);
                     lstrcat(@OutputString,ofn.lpstrFile+ofn.nFileOffset);
                     lstrcat(@OutputString,CrLf);
                     lstrcat(@OutputString,ExtensionName);
                     lstrcat(@OutputString,ofn.lpstrFile+ofn.nFileExtension);
                     MessageBox(hWnd,@OutputString,AppName,MB_OK);
                     FillChar(OutputString,OUTPUTSIZE,0);
                   end;
                 end
                 else DestroyWindow(hWnd);
    else WndProc := DefWindowProc(hWnd,uMsg,wParam,lParam);
  end;
end;

function WinMain(hInst,hPrevInst:HINST;CmdLine:LPSTR;CmdShow:longint) : 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.


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

©2024 mgr Jerzy Wałaszek

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

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