[Назад] [Далее]

7.3.5. Полноценное приложение

Теперь, когда мы знаем, как строятся программы с меню и диалогами, напишем одно настоящее полноценное приложение, включающее в себя все то, что требуется от программы, — меню, диалоги, комбинации клавиш для быстрого доступа к элементам меню и т.д. В качестве примера создадим простой текстовый редактор, аналогичный Notepad. В этом примере мы увидим, как получить параметры из командной строки, прочитать и записать файл, выделить и освободить память.

// winpad95.rc
// Файл ресурсов для программы winpad95.asm
// идентификаторы сообщений от пунктов меню
#define IDM_NEW             0x1001
#define IDM_OPEN            0x101L
#define IDM_SAVE            0x102L
#define IDM_SAVEAS          0x103L
#define IDM_EXIT            0x104L
#define IDM_ABOUT           0x105L
#define IDM_UNDO            0x106L
#define IDM_CUT             0x107L
#define IDM_COPY            0x108L
#define IDM_PASTE           0x109L
#define IDM_CLEAR           0x10AL
#define IDM_SETSEL          0x10BL

// идентификаторы основных ресурсов
#define IDJ1ENU             0x700L
#define ID_ACCEL            0x701L
#define ID_ABOUT            0x702L

// если есть иконка - можно раскомментировать эти две строки
// #define ID_ICON          0x703L
// ID_ICON ICON "winpad95.ico"

// основное меню
ID_MENU MENU DISCARDABLE {
        POPUP "&File;" {
                MENUITEM "&New;\tCtrl+N", IDM_NEW
                MENUITEM "&Open...;\tCtrl+O", IDM_OPEN
                MENUITEM "&Save;\tCtrl+S", IDM_SAVE
                MENUITEM "Save &As...;\tCtrl+Shift+S", IDM_SAVEAS
                MENUITEM SEPARATOR
                MENUITEM "E&xit;\tCtrl+Q", IDM_EXIT
        }
        POPUP "&Edit;" {
                MENUITEM "&Undo;\tCtrl-Z", IDM_UNDO
                MENUITEM SEPARATOR
                MENUITEM "Cu&t;\tCtrl-X", IDM_CUT
                MENUITEM "&Copy;\tCtrl-C", IDM_COPY
                MENUITEM "&Paste;\tCtrl-V", IDM_PASTE
                MENUITEM "&Delete;\tDel", IDM_CLEAR
                MENUITEM SEPARATOR
                MENUITEM "Select &All;\tCtrl-A", IDM_SETSEL
        }
        POPUP "&Help;" {
                MENUITEM "About", IDM_ABOUT
        }
}

// комбинации клавиш
ID_ACCEL ACCELERATORS DISCARDABLE {
        "N", IDM_NEW, CONTROL, VIRTKEY 
        "O", IDM_OPEN, CONTROL, VIRTKEY
        "S", IDM_SAVE, CONTROL, VIRTKEY
        "S", IDM_SAVEAS, CONTROL, SHIFT, VIRTKEY
        "Q", IDM_EXIT, CONTROL, VIRTKEY
        "Z", IDM_UNDO, CONTROL, VIRTKEY
        "A", IDM_SETSEL, CONTROL, VIRTKEY
}

// все эти определения можно заменить на #include <winuser.h>
#define DS_MODALFRAME       0x80L
#define DS_3DLOOK           4
#define WS_POPUP            0x80000000L
#define WS_CAPTION          0xC00000L
#define WS_SYSMENU          0x80000L
#define IDOK                1
#define IDC_STATIC          -1
#define IDI_APPLICATION     32512
#define WS_BORDER           0x800000L

// стандартный диалог "About"
ID_ABOUT DIALOG DISCARDABLE 0, 0, 125, 75
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Asmpad95"
{
        ICON                IDI_APPLICATION,IDC_STATIC,12,15,21,20
        CTEXT               "Asmpad95",IDC_STATIC,0,30,40,8
        CTEXT               "Prototype notepad-style editor for Windows 95
written entirely in assembly language",IDC_STATIC,45,10,70,45,WS_BORDER
        DEFPUSHBUTTON       "OK",IDOK,35,60,40,10
}

Теперь рассмотрим текст программы:

; winpad95.asm
; графическое win32-приложение - текстовый редактор
;
include def32.inc
include user32.inc
include kernel32.inc
include comdlg32.inc

ID_MENU            equ       700h
ID_ACCEL           equ       701h
ID_ABOUT           equ       702h

MAXSIZE            equ       260   ; максимальное имя файла
MEMSIZE            equ       65535 ; максимальный размер временного буфера в памяти

EditID             equ       1

        .386
        .model     flat
        .const
c_w_name           db  "Asmpad95",0 ; это и имя класса, и имя основного окна
edit_class         db  "edit",0     ; предопределенное имя класса для редактора
changes_msg        db  "Save changes?",0
filter_string      db  "All Files",0,'*.*',0  ; маски для Get * FileName
                   db  "Text Files",0, '*.txt',0,0

        .data
; структура, использующаяся Get * FileName
ofn     OPENFILENAME <SIZE ofn,?,?,offset filter_string,?,?,?,offset buffer,\
                         MAXSIZE,0,?,?,?,?,?,?,0,?,?,?>
; структура, описывающая наш основной класс
wc      WNDCLASSEX <SIZE WNDCLASSEX,CS_HREDRAW or CS_VREDRAW,offset win_proc,0,\
                         0,?,?,?,COLOR_WINDOW+1,ID_MENU,offset c_w_name,0>
flag_untitled      db    1     ; = 1, если имя файла не определено (новый файл)

        .data?
h_editwindow       dd    ?     ; идентификатор окна редактора
h_accel            dd    ?     ; идентификатор массива акселераторов
p_memory           dd    ?     ; адрес буфера в памяти
SizeReadWrite      dd    ?
msg_               MSG   <>
rec                RECT  <>
buffer             db    MAXSIZE dup(?)  ; имя файла
window_title       db    MAXSIZE dup(?), 12 dup(?)

        .code
_start:
        call       GetCommandLine      ; получить нашу командную строку
        mov        edi,eax
        mov        al,' '
        mov        ecx,MAXSIZE
        repne      scasb               ; найти конец имени нашей программы
        cmp        byte ptr [edi],0
        je         cmdline_empty
        mov        esi,edi
        mov        edi,offset buffer
        rep        movsb
        mov        flag_untitled,0
cmdline_empty:
; подготовить и зарегистрировать класс
        xor        ebx,ebx
        call       GetModuleHandle     ; определить наш идентификатор
        mov        esi,eax
        mov        wc.hInstance,eax    ; и сохранить его в wc.hInstance
        mov        ofn._hInstance,eax
        push       IDI_APPLICATION     ; или IDI_ICON, если иконка есть в ресурсах,
        push       ebx                 ; или esi, если иконка есть в ресурсах
        call       LoadIcon
        mov        wc.hIcon,eax
        push       IDC_ARROW           ; предопределенный курсор (стрелка)
        push       ebx
        call       LoadCursor
        mov        wc.hCursor,eax
        push       offset wc
        call       RegisterClassEx
; создать основное окно
        push       ebx
        push       esi
        push       ebx
        push       ebx
        push       200
        push       300
        push       CW_USEDEFAULT
        push       CW_USEDEFAULT
        push       WS_OVERLAPPEDWINDOW
        push       offset c_w_name
        push       offset c_w_name
        push       WS_EX_CLIENTEDGE
        call       СreateWindowEx
        push       eax                 ; для pop esi перед message_loop
        push       eax
        push       SW_SHOWNORMAL
        push       eax
        call       ShowWindow
        call       UpdateWindow
; инициализировать акселераторы
        push       ID_ACCEL
        push       esi
        call       LoadAcceleratоrs
        mov        h_accel,eax
; цикл ожидания сообщения
        pop        esi                 ; ESI - идентификатор основного окна
        mov        edi,offset msg_     ; EDI - структура с сообщением от него
message_loop:
        push       ebx
        push       ebx
        push       ebx
        push       edi
        call       GetMessage          ; получить сообщение,
        test       eax,eax             ; если это WM_OUIT, -
        jz         exit_msg_loop       ; выйти из цикла
        push       edi
        push       h_accel
        push       esi                 ; hWnd
        call       TranslateAccelerator ; преобразовать акселераторы в IDM*
        test       eax,eax
        jnz        message_loop
        push       edi
        call       TranslateMessage    ; преобразовать сообщения от клавиш
        push       edi
        call       DispatchMessage     ; и отослать обратно
        jmp        short message_loop
exit_msg_loop:
        push       msg_.wParam
        call       ExitProcess         ; конец программы

; процедура win_proc
;
; процедура не должна изменять регистры EBP,EDI,ESI и ЕВХ!
win_proc proc near
; параметры (с учетом push ebp)
    wp_hWnd     equ dword ptr [ebp+08h]
    wp_uMsg     equ dword ptr [ebp+0Ch]
    wp_wParam   equ dword ptr [ebp+10h]
    wp_lParam   equ dword ptr [ebp+14h]
; инициализируем стековый кадр
        push       ebp
        mov        ebp,esp             ; создать стековый кадр
        pusha                          ; сохранить все регистры
        xor        ebx,ebx             ; 0 для команд push 0
        mov        esi,wp_hWnd         ; для команд push hWnd
        mov        eax,wp_uMsg
; обработать пришедшее сообщение
        cmp        eax,WM_CREATE
        je         h_wm_create
        cmp        eax,WM_SIZE
        je         h_wm_size
        cmp        eax,WM_DESTROY
        je         h_wm_destroy
        cmp        eax,WM_COMMAND
        je         h_wm_command
        cmp        eax,WM_ACTIVATE
        je         h_wm_activate
        cmp        eax,WM_CLOSE
        je         h_wm_close
def_proc:
        popa
        leave                          ; если это ненужное сообщение,
        jmp        DefWindowProc       ; оставить его обработчику по умолчанию

; обработчик WM_CLOSE,
; если нужно, спрашивает, сохранить ли файл
h_wm_close:
        call       save_contents
        jmp        short def_proc

; обработчик WM_CREATE
;
h_wm_create:
; здесь также можно создать toolbar и statusbar
; создать окно редактора
        push       ebx
        push       wc.hInstance        ; идентификатор основной программы
        push       EditID
        push       esi                 ; hWnd
        push       ebx                 ; 0
        push       ebx                 ; 0
        push       ebx                 ; 0
        push       ebx                 ; 0
        push       WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or \
                   ES_AUTOHSCROLL or ES_AUTOVSCROLL
        push       ebx                 ; 0
        push       offset edit_class
        push       ebx                 ; 0
        call       CreateWindowEx
        mov        h_editwindow,eax
; передать ему фокус
        push       eax
        call       SetFocus
        cmp        flag_untitled,1
        je         continue_create
        call       skip_getopen        ; открыть файл, указанный в командной строке
continue_create:
        call       set_title
        jmp        end_wm_check

; обработчик WM_COMMAND
;
h_wm_command:
        mov        eax,wp_wParam
        cwde                           ; младшее слово содержит IDM_*
        sub        eax,100h
        jb         def_proc
; обработать сообщения от пунктов меню
        call       dword ptr menu_handlers[eax*4]
        jmp        end_wm_check

menu_handlers
        dd         offset h_idm_new,offset h_idm_open,offset h_idm_save
        dd         offset h_idm_saveas,offset h_idm_exit,offset h_idm_about
        dd         offset h_idm_undo, offset h_idm_cut, offset h_idm_copy
        dd         offset h_idm_paste, offset h_idm_clear, offset h_idm_setsel
; сообщения от пунктов меню должны быть описаны в win95pad.rc именно в таком
; порядке - от  IDM_NEW 100h до IDM_CLEAR 10Ah

h_idm_setsel:
        push       -1                  ; -1
        push       ebx                 ; 0
        push       EM_SETSEL           ; выделить весь текст
        push       h_editwindow
        call       SendMessage
        ret

; обработчики сообщений из меню EDIT:
h_idm_clear:
        mov        eax,WM_CLEAR
        jmp        short send_to_editor
h_idm_paste:
        mov        eax,WM_PASTE
        jmp        short send_to_editor
h_idm_copy:
        mov        eax,WM_COPY
        jmp        short send_to_editor
h_idm_cut:
        mov        eax,WM_CUT
        jmp        short send_to_editor
h_idm_undo:
        mov        eax,EM_UNDO
send_to_editor:
        push       ebx                 ; 0
        push       ebx                 ; 0
        push       eax
        push       h_editwindow
        call       SendMessage
        ret

; обработчик IDM_NEW
h_idm_new:
        call       save_contents       ; записать файл, если нужно
        mov        byte ptr flag_untitled,1
        call       set_title           ; отметить, что файл не назван
        push       ebx
        push       ebx
        push       WM_SETTEXT
        push       h_editwindow
        call       SendMessage         ; послать пустой WM_SETTEXT редактору
        ret

; обработчик IDM_ABOUT
h_idm_about:
        push       ebx                 ; 0
        push       offset about_proc
        push       esi                 ; hWnd
        push       ID_ABOUT
        push       wc.hInstance
        call       DialogBoxParam
        ret

; обработчик IDM_SAVEAS и IDM_SAVE
h_idm_save:
        cmp        flag_untitled, 1    ; если файл назван,
        jne        skip_getsave        ; пропустить вызов GetSaveFileName
h_idm_saveas:
; спросить имя файла
        mov        ofn.Flags,OFN_EXPLORER or OFN_OVERWRITEPROMPT
        push       offset ofn
        call       GetSaveFileName
        test       eax,eax
        jz         file_save_failed
skip_getsave:
; создать его
        push       ebx
        push       FILE_ATTRIBUTE_ARCHIVE
        push       CREATE_ALWAYS
        push       ebx
        push       FILE_SHARE_READ or FILE_SHARE_WRITE
        push       GENERIC_READ or GENERIC_WRITE
        push       offset buffer
        call       CreateFile
        mov        edi,eax
; выделить память
        push       MEMSIZE
        push       GMEM_MOVEABLE or GMEM_ZEROINIT
        call       GlobalAlloc
        push       eax                 ; hMemory для GlobalFree
        push       eax                 ; hMemory для GlobalLock
        call       GlobalLock
        mov        esi,eax             ; адрес буфера в ESI
; забрать текст из редактора
        push       esi
        push       MEMSIZE-1
        push       WM_GETTEXT
        push       h_editwindow
        call       SendMessage
; записать в файл
        push       esi                 ; pMemory
        call       lstrlen
        push       ebx
        push       offset SizeReadWrite
        push       eax                 ; размер буфера
        push       esi                 ; адрес буфера
        push       edi                 ; идентификатор файла
        call       WriteFile
        push       esi                 ; pMemory
        call       GlobalUnlock
        call       GlobalFree          ; hMemory уже в стеке
        push       edi                 ; идентификатор файла
        call       CloseHandle
; сбросить флаг модификации в редакторе
        push       ebx
        push       ebx
        push       EM_SETMODIFY
        push       h_editwindow
        call       SendMessage
        mov        byte ptr flag_untitled,0
        call       set_title
file_save_failed:
        push       h_editwindow
        call       SetFocus
        ret

; обработчик IDM_OPEN
h_idm_open:
        call       save_contents
; вызвать стандартный диалог выбора имени файла
        mov        ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or \
                   OFN_EXPLORER
        push       offset ofn
        call       GetOpenFileName
        test       eax,eax
        jz         file_open_failed
skip_getopen:
; открыть выбранный файл
        push       ebx
        push       FILE_ATTRIBUTE_ARCHIVE
        push       OPEN_EXISTING
        push       ebx
        push       FILE_SHARE_READ or FILE_SHARE_WRITE
        push       GENERIC_READ or GENERIC_WRITE
        push       offset buffer
        call       CreateFile
        mov        edi,eax             ; идентификатор для ReadFile
; выделить память
        push       MEMSIZE
        push       GMEM_MOVEABLE or GMEM_ZEROINIT
        call       GlobalAlloc
        push       eax                 ; hMemory для GlobalFree
        push       eax                 ; hMemory для GlobalLock
        call       GlobalLock          ; получить адрес выделенной памяти
        push       eax                 ; pMemory для GlobalUnlock
        push       eax                 ; pMemory для SendMessage
; прочитать файл
        push       ebx
        push       offset SizeReadWrite
        push       MEMSIZE-1
        push       eax                 ; pMemory для ReadFile
        push       edi
        call       ReadFile
; послать окну редактора сообщение wm_settext, чтобы он забрал текст из буфера
        push       ebx                 ; pMemory уже в стеке
        push       WM_SETTEXT
        push       h_editwindow
        call       SendMessage
; а теперь можно закрыть файл и освободить память
        call       GlobalUnlock        ; pMemory уже в стеке
        call       GlobalFree          ; hMemory уже в стеке
        push       edi                 ; hFile
        call       CloseHandle
        mov        byte ptr flag_untitled,0
        call       set_title
file_open_failed:
        push       h_editwindow
        call       SetFocus
        ret

; обработчик IDM_EXIT
h_idm_exit:
        call       save_contents
        push       esi                 ; hWnd
        call       DestroyWindow       ; уничтожить наше окно
        ret

; обработчик WM_SIZE
h_wm_size:
; здесь также надо послать WM_SIZE окнам toolbar и statusbar,
; изменить размер окна редактора так, чтобы оно по-прежнему было на все окно
        push       offset rec
        push       esi                 ; hWnd
        call       GetClientRect
        push       1                   ; true
        push       rec. bottom         ; height
        push       rec. right          ; width
        push       ebx                 ; у
        push       ebx                 ; x
        push       h_editwindow
        call       MoveWindow
        jmp        short end_wm_check

; обработчик WM_ACTIVATE
h_wm_activate:
        push       h_editwindow
        call       SetFocus
        jmp        short end_wm_check

; обработчик WM_DESTROY
h_wm_destroy:
        push       ebx
        call       PostQuitMessage     ; послать WM_QUIT основной программе

; конец процедуры window_proc
end_wm_check:
        рора
        xor        еах,еах      ; вернуть 0
        leave
        ret        16

; процедура set_title
; устанавливает новый заголовок для основного окна
set_title:
        push       esi
        push       edi
        mov        edi, offset window_title
        cmp        byte ptr flag_untitled,1 ; если у файла нет имени,
        je         untitled                 ; использовать Untitled
        mov        esi,ofn.lpstrFile        ; [ESI] - имя файла с путем
        movzx      eax,ofn.nFileOffset      ; eax - начало имени файла
        add        esi,eax
copy_filename:
        lodsb                          ; скопировать файл побайтно в название окна,
        test       al,al
        jz         add_progname        ; пока не встретится ноль
        stosb
        jmp        short copy_filename
add_progname:
        mov        dword ptr [edi],'-' ; приписать минус
        add        edi,3
        mov        esi,offset c_w_name
        mov        ecx,9               ; и название программы
        rep        movsb
        pop        edi
        pop        esi
        push       offset window_title
        push       esi                 ; идентификатор окна
        call       SetWindowText
        ret
untitled:
        mov        dword ptr [edil'itnU'     ; дописать "Unti"
        mov        dword ptr [edi+4],'delt'  ; дописать "tled"
        add        edi,8
        jmp        short add_progname

; процедура save_contents
; EBX = 0, ESI = hWnd
save_contents:
; спросить редактор, изменялся ли текст
        push       ebx
        push       ebx
        push       EM_GETMODIFY
        push       h_editwindow
        call       SendMessage
        test       eax,eax
        jz         not_modified
; спросить пользователя, сохранять ли его
        push       MB_YESNO + MB_ICONWARNING
        push       offset c_w_name
        push       offset changes_msg
        push       esi
        call       MessageBox
        cmp        eax,IDYES
        jne        not_modified
; сохранить его
        call       h_idm_save
not_modified:
        ret

win_proc endp

about_proc proc near
; параметры (с учетом push ebp)
    ap_hDlg        equ dword ptr [ebp+08h]
    ap_uMsg        equ dword ptr [ebp+0Ch]
    ap_wParam      equ dword ptr [ebp+10h]
    ap_lParam      equ dword ptr [ebp+14h]
        push       ebp
        mov        ebp,esp             ; создать стековый кадр
        cmp        ap_uMsg,WM_COMMAND
        jne        dont_proceed
        cmp        ap_wParam,IDOK
        jne        dont_proceed
        push       1
        push       ap_hDlg
        call       EndDialog
dont_proceed:
        xor        eax,eax             ; не обрабатывается
        leave
        ret        16
about_proc         endp

        end        _start

Размер этой программы — 6,5 Кб (скомпилированной ml/link), и даже версия, в которую добавлено все, что есть в Notepad (вывод файла на печать и поиск по тексту), все равно более чем в три раза меньше notepad.exe. Чем большее Windows-приложение создается, тем сильнее сказывается выигрыш в размерах при использовании ассемблера, даже несмотря на то, что мы только вызываем системные функции, практически не занимаясь программированием.

Прежде чем можно будет скомпилировать winpad95.asm, конечно, надо внести необходимые дополнения в наши включаемые файлы.

Добавления в файл def32.inc:

; из winuser.h
WM_CREATE               equ            1
WM_ACTIVATE             equ            6
WM_SETTEXT              equ            0Ch
WM_GETTEXT              equ            0Dh
WM_CUT                  equ            300h
WM_COPY                 equ            301h
WM_PASTE                equ            302h
WM_CLEAR                equ            303h
WM_UNDO                 equ            304h
WM_SIZE                 equ            5
WS_VISIBLE              equ            10000000h
WS_CHILD                equ            40000000h
WS_EX_CLIENTEDGE        equ            200h
ES_LEFT                 equ            0
ES_MUITILINE            equ            4
ES_AUTOHSCROLL          equ            80h
ES_AUTOVSCROLL          equ            40h
EM_GETHANDLE            equ            0BDh
EM_GETMODIFY            equ            0B8h
EM_SETMODIFY            equ            0B9h
EM_UNDO                 equ            0C7h
EM_SETSEL               equ            0B1h
MB_YESNO                equ            4
MB_ICONWARNING          equ            30h
IDOK                    equ            1
IDYES                   equ            6

; из winnt.h
GENERIC_READ            equ            80000000h
GENERIC_WRITE           equ            40000000h
FILE_SHARE_READ         equ            1
FILE_SHARE_WRITE        equ            2
FILE_ATTRIBUTE_ARCHIVE  equ            20h

; из commdlg.h
OFN_PATHMUSTEXIST       equ            800h
OFN_FILEMUSTEXIST       equ            1000h
OFN_EXPLORER            equ            80000h
OFN_OVERWRITEPROMPT     equ            2
OPENFILENAME            struc
        IStructSize          dd        ?
        hwndOwner            dd        ?
        _hInstance           dd        ?
        lpstrFilter          dd        ?
        lpstrCustomFilter    dd        ?
        nMaxCustFilter       dd        ?
        nFilterlndex         dd        ?
        lpstrFile            dd        ?
        nMaxFile             dd        ?
        lpstrFileTitle       dd        ?
        nMaxFileTitle        dd        ?
        lpstrInitialDir      dd        ?
        lpstrTitle           dd        ?
        Flags                dd        ?
        nFileOffset          dw        ?
        nFileExtension       dw        ?
        lpstrDefExt          dd        ?
        lCustData            dd        ?
        lpfnHook             dd        ?
        lpTemplateName       dd        ?
OPENFILENAME            ends

; из windef.h
RECT                    struc
        left                 dd        ?
        top                  dd        ?
        right                dd        ?
        bottom               dd        ?
RECT                    ends

; из winbase.h
GMEM_MOVEABLE           equ            2
GMEM_ZEROINIT           equ            40h
OPEN_EXISTING           equ            3
CREATE_ALWAYS           equ            2

Добавления в файл kernel32.inc между ifdef _TASM_ и else:

                        extrn          lstrlen:near
                        extrn          GetCommandLineA:near
                        extrn          CloseHandle:near
                        extrn          GlobalAlloc:near
                        extrn          GlobalLock:near
                        extrn          GlobalFree:near
                        extrn          CreateFileA:near
                        extrn          ReadFile:near
                        extrn          WriteFile:near
GetCommandLine          equ            GetCommandLineA
CreateFile              equ            CreateFileA

и между else и endif:

                        extrn          __imp__lstrlen@4:dword
                        extrn          __imp__GetCommandLineA@0:dword
                        extrn          __imp__CloseHandle@4:dword
                        extrn          __imp__GlobalAlloc@8:dword
                        extrn          __imp__GlobalLock@4:dword
                        extrn          __imp__GlobalFree@4:dword
                        extrn          __imp__CreateFileA@28:dword
                        extrn          __imp__ReadFile@20:dword
                        extrn          __imp__WriteFile@20:dword
lstrlen                 equ            __imp__lstrlen@4
GetCommandLine          equ            __imp__GetCommandLineA@0
CloseHandle             equ            __imp__CloseHandle@4
GlobalAlloc             equ            __imp__GlobalAlloc@8
GlobalLock              equ            __imp__GlobalLock@4
GlobalFree              equ            __imp__GlobalFree@4
CreateFile              equ            __imp__CreateFileA@28
ReadFile                equ            __imp__ReadFile@20
WriteFile               equ            __imp__WriteFile@20

Добавления в файл user32.inc:

                        extrn          LoadAcceleratorsA:near
                        extrn          TranslateAccelerator:near
                        extrn          SendMessageA:near
                        extrn          SetWindowTextA:near
                        extrn          MoveWindow:near
                        extrn          GetClientRect:near
                        extrn          GlobalUnlock:near
LoadAccelerators        equ            LoadAcceleratorsA
SendMessage             equ            SendMessageA
SetWindowText           equ            SetWindowTextA

и между else и endif:

                        extrn          __imp__LoadAcceleratorsA@8:dword
                        extrn          __imp__ТranslateAccelerator@12:dword
                        extrn          __imp__SendMessageA@16:dword
                        extrn          __imp__SetWindowTextA@8:dword
                        extrn          __imp__MoveWindow@24:dword
                        extrn          __imp__GetClientRect@8:dword
                        extrn          __imp__GlobalUnlock@4:dword
LoadAccelerators        equ            __imp__LoadAcceleratorsA@8
TranslateAccelerator    equ            __imp__TranslateAccelerator@12
SendMessage             equ            __imp__SendMessageA@16
SetWindowText           equ            __imp__SetWindowTextA@8
MoveWindow              equ            __imp__MoveWindow@24
GetClientRect           equ            __imp__GetClientRect@8
GlobalUnlock            equ            __imp__GlobalUnlock@4

Кроме того, нам потребуется новый включаемый файл, comdlg32.inc, описывающий функции, связанные с вызовами стандартных диалогов (выбор имени файла, печать документа, выбор шрифта и т.д.):

; comdlg32.inc
; включаемый файл с функциями из comdlg32.dll
ifdef _TASM_
        includelib import32.lib
                        extrn          GetOpenFileNameA:near
                        extrn          GetSaveFileNameA:near
        GetOpenFileName equ            GetOpenFileNameA
        GetSaveFileName equ            GetSaveFileNameA
else
        includelib comdlg32.lib
; истинные имена используемых функций
                        extrn          __imp__GetOpenFileNameA@4:dword
                        extrn          __imp__GetSaveFileNameA@4:dword
; присваивания для удобства использования
        GetOpenFileName equ            __imp__GetOpenFileNameA@4
        GetSaveFileName equ            __imp__GetSaveFileNameA@4
endif

Конечно, эту программу можно еще очень долго развивать — добавить toolbar и statusbar, написать документацию, можно сделать так, чтобы выделялось не фиксированное небольшое количество памяти для переноса файла в редактор, а равное его длине. Можно также воспользоваться функциями отображения части файла в память (CreateFileMapping, OpenFileMapping, MapViewOfFile, UnmapViewOfFile), позволив работать с неограниченно большими файлами. Win32 API настолько богат функциями, что можно довольно долго заниматься только их изучением, а это относится к теме программирования на ассемблере ровно настолько, насколько относится к программированию на любом другом языке.


п»ї
"target=_blank><\/a>") //-->