.386 ;допустимы команды и регистры 386+ процессора, ; кроме того, необходимо для модели flat.MODEL FLAT,STDCALL ;плоская модель памяти flat (все адресуется только смещениями) ;необходима для программ под Windows ; кроме того, STDCALL задает способ передачи параметров через стек ; (первым передается последний) и способ извлечения параметров ; из стека (по RET <n>). Этот способ используется почти всеми WinAPIlocals ;Разрешение идентификаторов с локальной областью действияjumps ;Разрешение автоматического решения проблемы коротких адресов ; в командах условного переходаUNICODE = 0 ;Будем использовать ANSI строки ;Не сильно и нужна, нигде не используется... ;Везде явно упоминаются ANSI-версии.include win32.inc ;описание констант, структур, внешних именincludelib import32.lib ;библиотека импортаIDC_STATIC equ -1 ;ID неизменяемых статических строкIDD_DIALOG1 equ 103 ;ID основного диалогаIDD_DIALOG2 equ 104 ;ID диалога AboutIDI_ICON equ 105 ;ID иконки 32х32 (не используется)IDC_EDIT1 equ 1000 ;ID Edit-а "Drive Letter:"IDC_EDIT2 equ 1001 ;ID Edit-а "Секторов в кластере"IDC_EDIT3 equ 1002 ;ID Edit-а "Байт в секторе"IDC_EDIT4 equ 1003 ;ID Edit-а "Свободных кластеров"IDC_EDIT5 equ 1004 ;ID Edit-а "Всего кластеров"IDC_EDIT6 equ 1005 ;ID Edit-а "Max filename length:"IDC_EDIT7 equ 1006 ;ID Edit-а "File system flags: "IDC_EDIT8 equ 1007 ;ID Edit-а "Тип носителя"IDC_EDIT9 equ 1008 ;ID Edit-а "Метка тома"IDC_EDIT10 equ 1009 ;ID Edit-а "Серийный номер"IDC_EDIT11 equ 1010 ;ID Edit-а "Файловая система"IDC_EDIT12 equ 1011 ;ID Edit-а "Network Name:"IDC_EDIT13 equ 1012 ;ID Edit-а "Общая ёмкость"IDC_EDIT14 equ 1013 ;ID Edit-а "Свободно"IDC_TEXT1 equ 3000 ;ID STATIC Control-а "Drive Letter:" (можно было использовать IDC_STATIC)IDC_TEXT2 equ 3001 ;ID STATIC Control-а "Секторов в кластере" (можно было использовать IDC_STATIC)IDC_TEXT3 equ 3002 ;ID STATIC Control-а "Байт в секторе" (можно было использовать IDC_STATIC)IDC_TEXT4 equ 3003 ;ID STATIC Control-а "Свободных кластеров" (можно было использовать IDC_STATIC)IDC_TEXT5 equ 3004 ;ID STATIC Control-а "Всего кластеров" (можно было использовать IDC_STATIC)IDC_TEXT6 equ 3005 ;ID STATIC Control-а "Max filename length:" (можно было использовать IDC_STATIC)IDC_TEXT7 equ 3006 ;ID STATIC Control-а "File system flags: " (можно было использовать IDC_STATIC)IDC_TEXT8 equ 3007 ;ID STATIC Control-а "Тип носителя" (можно было использовать IDC_STATIC)IDC_TEXT9 equ 3008 ;ID STATIC Control-а "Метка тома" (можно было использовать IDC_STATIC)IDC_TEXT10 equ 3009 ;ID STATIC Control-а "Серийный номер" (можно было использовать IDC_STATIC)IDC_TEXT11 equ 3010 ;ID STATIC Control-а "Файловая система" (можно было использовать IDC_STATIC)IDC_TEXT12 equ 3011 ;ID STATIC Control-а "Network Name:". Этот ID нужен, мы с этим STATIC работаемICON_SMALL equ 0 ;ID иконки 16х16 (не используется)IDDEC equ 2000 ;ID кнопки "Back"IDINC equ 2001 ;ID кнопки "Next"IDEXIT equ 2003 ;ID кнопки "Exit"IDHLP equ 2002 ;ID не используемой кнопки "Help"IDM_ABO equ 4001 ;ID команды из меню "Help\About"IDM_EXIT equ 4002 ;ID команды из меню "File\Exit".DATA ;Сегмент данных ;Глобальные переменныеhInst dd ? ;handle экземпляра программыhIcon dd ? ;handle иконки (не используется)fmat1 db "%lu", 0 ;Формат "длинный целый" для преобразования числа в строкуfmat2 db "%lX", 0 ;Формат "длинный 16-ричный" для преобразования числа в строкуmsg MSGSTRUCT <?> ;Структура, необходимая для обработки сообщений системыpnt PAINTSTRUCT <?> ;Структура, необходимая для рисования по WM_PAINTrect RECT <> ;Структура для координат прямоугольной зоны чего-либоDlgWidth dd ? ;Переменная для сохранения ширины диалогаDlgHeight dd ? ;Переменная для сохранения высоты диалогаDesktopRect RECT <> ;Структура для координат прямоугольной зоны "рабочего стола"cdrive db ‘a:\‘, 0 ;Начальная строка, задающая корневой путь текущего устройстваddrive db ‘a‘ ;текущее устройствоDriveType dd 0 ;Тип устройстваTot_clust dd 0 ;Общее число кластеровFree_clust dd 0 ;Число свободных кластеровBytesPSect dd 0 ;Байтов на секторSectPClust dd 0 ;Секторов на кластерvol_filenames equ 16 ;Длина имени файловой системыvol_filename db vol_filenames dup(0) ;Имя файловой системы (FAT, NTFS...)vol_filesys dd 0 ;Файловая системаvol_Maxfilelen dd 0 ;Максимальная длина именvol_serial dd 0 ;Серийный номерvol_Names equ 16 ;Длина имени томаvol_Name db vol_Names dup(0) ;Имя томаnet_Names dd 32 ;Длина запрашиваемой информацииnet_Name db 32 dup(0) ;Сетевое имяnumbuff db 64 dup(0) ;Буфер для преобразования числа в строкуTypeTab dd offset nullst ;Таблица имен типов устройств dd offset nullst dd offset TypeID2 ;2 - дискета, флэш dd offset TypeID3 ;3 - жесткий диск dd offset TypeID4 ;4 - сетевой диск dd offset TypeID5 ;5 - CD, DVD dd offset TypeID6 ;6 - Memory diskTypeID2 db ‘ (Removable)‘, 0,0,0,0TypeID3 db ‘ (Fixed)‘, 0,0,0,0,0,0,0,0TypeID4 db ‘ (Network)‘, 0,0,0,0,0,0TypeID5 db ‘ (CD-ROM)‘, 0,0,0,0,0,0,0TypeID6 db ‘ (RamDisk)‘, 0,0,0,0,0,0nullst db 16 dup(0) ;Пустая строка.CODE ;Сегмент кода;----------------------------------------------------------------------main: ;Точка входа; mov eax, offset jjj ;Это лишнее, видать осталсь от каких-то экспериментов call GetModuleHandle, NULL ;Получим handle приложения mov hInst, eax ;Сохраним call DialogBoxParamA, hInst, IDD_DIALOG1, 0, offset DlgProc, 0 ;Создадим основной диалог IDD_DIALOG1 из ресурсов ;нашего приложения (hInst) с функцией окна DlgProc call ExitProcess ;Выход ;Из дальнейшей логики можно увидеть, что сюда мы никогда не попадем... ;Программа вызывает ExitProcess в отработке WM_DESTROY... ;----------------------------------------------------------------------DlgProc PROC hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD ;Функция окна диалога mov eax, wmsg ;Анализируем приходящие сообщения cmp ax, WM_DESTROY ;Сообщение приходит, когда завершаем диалог je wmdestroy cmp ax, WM_CLOSE ;Сообщение приходит, когда нажимаем на кнопку "х" на заголовке окна je wmdestroy cmp ax, WM_COMMAND ;Сообщение приходит, когда нажимаем на кнопки диалога je wmcommand cmp ax, WM_INITDIALOG ;Сообщение приходит в начале инициализации диалога je initdlg cmp ax, WM_PAINT ;Сообщение приходит при перерисовке окна je paint xor eax,eax ;Остальные сообщения не отрабатываем ret;----------------------------------------------------------------------wmdestroy: call EndDialog, hwnd, 0 ;Завершаем диалог call ExitProcess ;Выход из программы (смотри замечание выше) ;Где-то можно убрать, "правильнее" здесь ret;----------------------------------------------------------------------wmcommand: cmp wparam, IDEXIT ;Кнопка "Exit"? je wmdestroy ;Идем сразу на завершение диалога ;"Правильнее" послать себе сообщение SendMessage(hwnd,WM_CLOSE,0,0) cmp wparam, IDINC ;Кнопка "Next"? jne noinc ; Нет? идем на дальнейшую проверку call GetDlgItem, hwnd, IDDEC ;Handle кнопки "Back" call EnableWindow, eax, true ;Разрешаем кнопку mov al, byte ptr [offset cdrive] ; сохраним текущую букву устройства mov byte ptr [offset ddrive], al ; в ddrivelb_1: inc byte ptr [offset cdrive] ;Инкрементируем букву устройства cmp byte ptr [offset cdrive], ‘z‘ ;Дошли до последней возможной? jbe notou1 ;Если нет, то отрабатываем mov al, byte ptr [offset ddrive] ;Иначе, mov byte ptr [offset cdrive], al ; восстанавливаем последнее значение call GetDlgItem, hwnd, IDINC ;Handle кнопки "Next" call EnableWindow, eax, false ;Запрещаем кнопку retnotou1: ;Буква корректна call GetDriveTypeA, offset cdrive ;Получаем тип устройства cmp eax, 1 ;Если 0 или 1, то такого устройства нет jbe lb_1 ;Идем на поиск следующего устройства call GetDriveI, hwnd ;Получаем и показываем информацию об устройстве ret;----------------------------------------------------------------------noinc: cmp wparam, IDDEC ;Кнопка "Back"? jne nodec ; Нет? идем на дальнейшую проверку call GetDlgItem, hwnd, IDINC ;Handle кнопки "Next" call EnableWindow, eax, true ;Разрешаем кнопку mov al, byte ptr [offset cdrive] ; сохраним текущую букву устройства mov byte ptr [offset ddrive], al ; в ddrivelb_2: dec byte ptr [offset cdrive] ;Декркментируем букву устройства cmp byte ptr [offset cdrive], ‘a‘ ;Дошли до первой? jae notou2 ;Если нет, то отрабатываем mov al, byte ptr [offset ddrive] ;Иначе, mov byte ptr [offset cdrive], al ; восстанавливаем последнее значение call GetDlgItem, hwnd, IDDEC ;Handle кнопки "Back" call EnableWindow, eax, false ;Запрещаем кнопку retnotou2: ;Буква корректна call GetDriveTypeA, offset cdrive ;Получаем тип устройства cmp eax, 1 ;Если 0 или 1, то такого устройства нет jbe lb_2 ;Идем на поиск следующего устройства call GetDriveI, hwnd ;Получаем и показываем информацию об устройстве retnodec: cmp wparam, IDM_ABO ;Кнопка "Exit"? jne nohlp ; Нет? идем на дальнейшую проверку call GetModuleHandle, NULL ;Получим handle приложения ;Хотя мы его уже храним в hInst... call DialogBoxParamA, eax, IDD_DIALOG2, hwnd, offset DlgProc2, 0 ;Создадим диалог "About" IDD_DIALOG2 из ресурсов ;нашего приложения с функцией окна DlgProc2 ret ;Пропущена команда... ; Хотя работает и без нее, просто отработает по следующей ret...nohlp: cmp wparam, IDM_EXIT ;Кнопка "Exit"? jne noext ; Нет? Заканчиваем анализ jmp wmdestroy ;Завершаем диалог ;"Правильнее" послать себе сообщение SendMessage(hwnd,WM_CLOSE,0,0)noext: xor eax, eax ;Остальное не наше ret;---------------------------------------initdlg: ;Начальная инициализация диалога; call LoadIcon, hInst, IDI_ICON; mov hIcon, eax call GetWindowRect, hwnd, offset rect ;Получим координаты окна диалога call GetDesktopWindow ;Получим handle "рабочего стола" call GetWindowRect, eax, offset DesktopRect ;Получим координаты окна "рабочего стола" ;Отцентрируем наше окно mov eax, rect.rcBottom sub eax, rect.rcTop ;В EAX высота нашего диалога mov DlgHeight, eax ;Сохраним mov eax, rect.rcRight sub eax, rect.rcLeft ;В EAX ширина нашего диалога mov DlgWidth, eax ;Сохраним mov ebx, DesktopRect.rcBottom ;В EBX высота "рабочего стола" sub ebx, DlgHeight ;Минус высота диалога shr ebx, 1 ;Пополам, получим в EBX стартовый Y диалога mov ecx, DesktopRect.rcRight ;В ECX ширина "рабочего стола" sub ecx, DlgWidth ;Минус ширина диалога shr ecx, 1 ;Пополам, получим в ECX стартовый X диалога call MoveWindow, hwnd, ecx, ebx, DlgWidth, DlgHeight, 0 ;Перемещаем диалог call GetDriveI, hwnd ;И показываем информацию об первом устройстве (А:) ;Кстати, если устройства A нет в системе, то будут пустые поля ... ;"Правильнее", наверное, сделать как по кнопке "Next": ; с проверкой и автоинкрементом... Впрочем, допустимо и так... ret;----------------------------------------------------------------------paint: ;Отрисовка окна ;Вообще говоря, она лишняя (когда было рисование иконки,то было нужно...) ;Система все равно сама отрисовывает call BeginPaint, hwnd, offset pnt ;Начало; push hIcon ; Icon Handle; push 204 ; Start Y; push 10 ; Start X; push eax ; The hDc (returned by BeginPaint); call DrawIcon ; Draw it call EndPaint, hwnd, offset pnt ;Конец retDlgProc endp ;Конец функции окна основного диалога;----------------------------------------------------------------------DlgProc2 PROC hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD ;Функция окна диалога "About" mov eax, wmsg ;Все аналогично cmp ax, WM_DESTROY je wmdestroy2 cmp ax, WM_CLOSE je wmdestroy2 cmp ax, WM_COMMAND je wmcommand2 cmp ax, WM_INITDIALOG je initdlg2 cmp ax, WM_PAINT je paint2 xor eax,eax ret;----------------------------------------------------------------------wmdestroy2: call EndDialog, hwnd, 0 retpaint2: call BeginPaint, hwnd, offset pnt call EndPaint, hwnd, offset pnt retinitdlg2: ;Аналогично, центрируем окно call GetWindowRect, hwnd, offset rect call GetDesktopWindow call GetWindowRect, eax, offset DesktopRect mov eax, rect.rcBottom sub eax, rect.rcTop mov DlgHeight, eax ;Высота окна mov eax, rect.rcRight sub eax, rect.rcLeft mov DlgWidth, eax ;Ширина окна mov ebx, DesktopRect.rcBottom sub ebx, DlgHeight shr ebx, 1 ;ebx = Start y mov ecx, DesktopRect.rcRight sub ecx, DlgWidth shr ecx, 1 ;ecx = Start x call MoveWindow, hwnd, ecx, ebx, DlgWidth, DlgHeight, 0 ; Центрируем retwmcommand2: cmp wparam, IDOK ;Выходим по кнопке "Ok" jne nook jmp wmdestroy2nook: retDlgProc2 endp;----------------------------------------------------------------------GetDriveI proc hDlg:dword ;Получение и отображение информации об устройстве ;Параметр - handle диалога call SetDlgItemTextA, hDlg, IDC_EDIT1, offset cdrive ;Задаем путь корня диска call GetDriveTypeA, offset cdrive ;Проверим тип диска cmp eax, 1 ;Если 0 или 1, то выходим, поля останутся незаполненными jbe notva ; (см замечание для initdlg основного окна) mov DriveType, eax ;Сохраним call jprintf, offset numbuff, offset fmat1, DriveType;Преобразуем число типа в символьную строку в буфере numbuff mov esi, offset numbuff ;адрес буфераfend1: ;Цикл поиска позиции завершающего нуля lodsb ;Читаем очередной байт, esi автоматом инкрементируется or al, al ;проверим на 0 jnz fend1 ;повторим dec esi ;esi - адрес нуля mov edi, esi ;сохраним в edi адрес, куда писать mov esi, DriveType ;Номер типа cmp esi, 6 ;Проверим на максимальный ja nocand ;Для неизвестного типа пропустим добавление текста mov esi, dword ptr [offset TypeTab + esi*4] ;В esi адрес строки из таблицы mov ecx, 16 ;длина строки rep movsb ;копируя [esi]->[edi], добавим название типа носителя mov eax, true cmp DriveType, 4 ;Для сетевого диска разрешим "Network Name" je isnetw mov eax, false ;Для всех остальных запрещаемisnetw: push eax ;true/false для EnableWindow call GetDlgItem, hwnd, IDC_TEXT12 ;Получим handle STATIC-а "Network Name" push eax call EnableWindow ;Enable/Disable STATIC-аnocand: call SetDlgItemTextA, hDlg, IDC_EDIT8, offset numbuff;Передадим сформированную строку в Edit "Тип носителя" push offset Tot_clust ;Общее число кластеров push offset Free_clust ;Число свободных кластеров push offset BytesPSect ;Байтов на сектор push offset SectPClust ;Секторов на кластер push offset cdrive ;устройство call GetDiskFreeSpaceA ;Получим информацию об устройстве, параметрами адреса соотв.перем. ;Сформируем соответствующие числовые строки ; и передадим в соответствующий Edit для отображения call jprintf, offset numbuff, offset fmat1, SectPClust call SetDlgItemTextA, hDlg, IDC_EDIT2, offset numbuff ;Секторов на кластер call jprintf, offset numbuff, offset fmat1, BytesPSect call SetDlgItemTextA, hDlg, IDC_EDIT3, offset numbuff ;Байтов на сектор call jprintf, offset numbuff, offset fmat1, Free_clust call SetDlgItemTextA, hDlg, IDC_EDIT4, offset numbuff ;Число свободных кластеров call jprintf, offset numbuff, offset fmat1, Tot_clust call SetDlgItemTextA, hDlg, IDC_EDIT5, offset numbuff ;Общее число кластеров;jjj: ;Непонятно зачем... mov eax, Tot_clust ;Посчитаем общую ёмкость; cdq ;Лишнее imul SectPClust imul BytesPSect ;edx:eax = Tot_clust * SectPClust * BytesPSect байт call PutBytes ;Преобразуем в строку, с учетом Гбайт, Мбайт... call SetDlgItemTextA, hDlg, IDC_EDIT13, offset numbuff ;передадим в Edit для отображения mov eax, Free_clust ;Посчитаем общий свободный объём; cdq ;Лишнее imul SectPClust imul BytesPSect ;edx:eax = Free_clust * SectPClust * BytesPSect байт call PutBytes ;Преобразуем в строку, с учетом Гбайт, Мбайт... call SetDlgItemTextA, hDlg, IDC_EDIT14, offset numbuff ;передадим в Edit для отображения;---------------------------------------------------------------------- push vol_filenames ;Длина имени файловой системы push offset vol_filename ;Имя файловой системы (FAT, NTFS...) push offset vol_filesys ;Флаги Файловой системы push offset vol_Maxfilelen ;Максимальная длина имен push offset vol_serial ;Серийный номер push vol_Names ;Длина имени тома push offset vol_Name ;Имя тома push offset cdrive ;устройство call GetVolumeInformationA ;Запросим информацию о томе ;Если надо, сформируем соответствующие числовые строки ; и передадим в соответствующий Edit для отображения call jprintf, offset numbuff, offset fmat1, vol_Maxfilelen call SetDlgItemTextA, hDlg, IDC_EDIT6, offset numbuff ;Максимальная длина имен call jprintf, offset numbuff, offset fmat2, vol_filesys call SetDlgItemTextA, hDlg, IDC_EDIT7, offset numbuff ;Флаги Файловой системы в HEX call jprintf, offset numbuff, offset fmat2, vol_serial call SetDlgItemTextA, hDlg, IDC_EDIT10, offset numbuff ;Серийный номер в HEX call SetDlgItemTextA, hDlg, IDC_EDIT11, offset vol_filename ;Имя файловой системы (FAT, NTFS...) call SetDlgItemTextA, hDlg, IDC_EDIT9, offset vol_Name ;Имя тома;---------------------------------------------------------------------- ;И, наконец, запросим сетевое имя ;Опять же, "правильнее" было бы запрашивать только для типа 4 ;Для всех остальнее очищать... push offset net_Names ;Длина поля сетевого имени push offset net_Name ;Адрес сетевого имени push 1 ;Тип запрашиваемой информации push offset cdrive ;Устройство call WNetGetUniversalNameA ;Запросим сетевое имя mov esi, dword ptr [offset net_Name] ;получим адрес строки or esi, esi ;Проверим ответ jnz nonet1 ;Что-то есть mov esi, offset nullst ;Иначе пустая строкаnonet1: call SetDlgItemTextA, hDlg, IDC_EDIT12, esi ;Отобразим в Edit-еnotva: retGetDriveI endp;----------------------------------------------------------------------------;PutBytes proc ;Преобразуем число EDX:EAX в строку, с учетом Гбайт, Мбайт... or edx, edx ;Если edx != 0, то > 4Гб jnz isbig3 ;И тогда считаем в Гб cmp eax, 1024 ;Если > 1024, jae isbig1 ; то считаем в Кб или Мб или Гб call jprintf, offset numbuff, offset fmat1, eax ;Байты ret ;И выходимisbig1: ;Число > 1024 cmp eax, 1024*1024 ;Если число > 1024*1024 jae isbig2 ; то считаем в Мб или Гб mov si, ‘bK‘ ;Иначе, в Кбdok: ;Формирование числа mov ecx, 1024 mov ebx, 1000 idiv ecx ;Разделим на 1024 mov ecx, eax ;ecx = частное, edx = остаток mov eax, edx ;Остаток - число 0-1023; cdq ;лишнее ;Чтобы отобразить остаток как тысячные, ; промасштабируем: умножим на 1000 и разделим на 1024 ; в результате получим число 0-999 imul ebx ;Умножим на 1000 mov ebx, 1024 idiv ebx ;Разделим на 1024 push esi ;Сохраним единицы измерения push eax ;Сохраним остаток call jprintf, offset numbuff, offset fmat1, ecx ;Сформируем строку из целого числа Гб, Мб, Кб pop eax ;Восстановим остаток call fendnum ;Ищем в numbuff позицию нуля, результат в edi mov byte ptr [edi], ‘.‘ ;разделяем целую часть числа от дробной точкой inc edi ; cmp eax, 100 ;Число из трех знаков, jae okl1 ;Если да, то преобразовываем mov byte ptr [edi], ‘0‘ ;Иначе, десятые - 0 inc edi ; cmp eax, 10 ;Число из двух знаков, jae okl1 ;Если да, то преобразовываем mov byte ptr [edi], ‘0‘ ;Иначе, сотые - 0 inc ediokl1: call jprintf, edi, offset fmat1, eax ;Формируем числовую строку ;(Можно было задать формат "%3.3u", и весь анализ не нужен...) call fendnum ;Ищем в numbuff позицию нуля, результат в edi pop esi ;Восстановим в si единицы измерения mov byte ptr [edi], ‘ ‘ ;Разделительный пробел mov word ptr [edi + 1], si ;Пишем mov byte ptr [edi + 3], 0 ;Конец строки ret ;Строка готова - выходимisbig2: ;Число > 1024*1024 cmp eax, 1024*1024*1024 ;Если > 1024*1024*1024, jae isbig3 ; то считаем в Гб ; иначе в Мб mov ecx, 1024 ;Считаем сколько Мб, idiv ecx ; для этого делим на 1024 cdq ;Подготовим edx для последующего деления mov si, ‘bM‘ ;Единица измерения jmp dok ;На формирование строки isbig3: ;Число > 1024*1024*1024 mov ecx, 1024 * 1024 ;Считаем в Гб idiv ecx ; для этого делим на 1024*1024 cdq ;Подготовим edx для последующего деления mov si, ‘bG‘ ;Единица измерения jmp dok ;На формирование строкиPutBytes endp;----------------------------------------------------------------------------;fendnum proc ;Ищем в numbuff позицию нуля, результат в edi mov edi, offset numbuff ; Тут понятно и без комментариев...lopfs: cmp byte ptr [edi], 0 je fouio inc edi jmp lopfsfouio: retfendnum endpjprintf proc p1:dword, p2:dword, p3:dword ;Обертка для вызова wsprintf для преобразования числа в строку push p3 ;У этой ф-ии способ передачи параметров - С push p2 ;Параметры передаются, начиная с последнего push p1 call _wsprintfA add esp, 12 ;Выкидывает вызывающая программа с помощью add esp,<n> retjprintf endp;----------------------------------------------------------------------ends end main ;Конец текста, точка входа - main