Трансляция.
1-й способ.
tasm32 /ml dialforc.asm brcc32 dialforc.rcДалее включаем в проект для программы на Рис. 3.7.5 файлы
dialforc.obj
и dialforc.res
.
2-й способ.
Отличается от предыдущего тем, что в проект включается файл
dialforc.rc
, а не dialforc.res
. Разумеется,
определения констант оттуда следует убрать, т.к. они имеются в подключаемых Си
head-файлах.
IV
Здесь рассматривается пример простейшего калькулятора. Для ассемблера часто сложно найти библиотеки с определенными процедурами, писать же все самому - не хватит времени. Предлагаемая схема очень проста. По сути, программа на языке Си (или другом языке высокого уровня) является неким каркасом. Она вызывает процедуру на языке ассемблера, которая и выполняет основные действия. Кроме того, в Си-модуле можно поместить и другие процедуры, которые легче написать на Си и которые будут вызываться из ассемблера. Здесь как раз и приводится такой пример. В Си-модуле я поместил процедуры, преобразующие строки в вещественные числа, выполняющие над ними действия и затем преобразующие результат опять в строку.
// calcc.срр #include <windows.h> #include <stdio.h> // вызов главной ассемолернои процедуры extern "С" _stdcall MAIN1(); // сложить extern "С" _stdcall void sum(char *, char *, char *); // вычесть extern "C" _stdcall void su(char *, char *, char *); // умножить extern "C" _stdcall void mu(char *, char *, char *); // разделить extern "C" _stdcall void dii(char *, char *, char *); int WINAPI WinMain (HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode) { MAIN1(); return 0; } extern "C" _stdcall void sum(char * s1, char * s2, char * s) { float f1,f2,f; f1=atof(s1); f2=atof(s2); f=f1+f2; sprintf(s,"%f",f); strcat(s," +"); return; } extern "C" _stdcall void su(char * s1, char * s2, char * s) { float f1,f2,f; f1=atof(s1); f2=atof(s2); f=f1-f2; sprintf(s,"%f",f); strcat(s," -"); return; } extern "C" _stdcall void mu(char * s1, char * s2, char * s) { float f1,f2,f; f1=atof(s1); f2=atof(s2); f=f1*f2; sprintf(s,"%f",f); strcat(s," *"); return; } extern "C" __stdcall void dii(char * s1, char * s2, char * s) { float f1,f2,f; f1=atof(s1); f2=atof(s2); if(f2!=0) { f=f1/f2; sprintf(s,"%f",f); strcat(s," /"); } else strcpy(s,"Ошибка деления"); return; }Рис. 3.7.7. Си-модуль для программы простейшего калькулятора, компонуемый с ассемблерным модулем на Рис. 3.8.8.
// calc.rc // определение констант // стили окна #define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define DS_3DLOOK 0x0004L #define ES_LEFT 0x0000L #define WS_CHILD 0x40000000L #define WS_VISIBLE 0x10000000L #define WS_BORDER 0x00800000L #define WS_TABSTOP 0x00010000L #define SS_LEFT 0x00000000L #define BS_PUSHBUTTON 0x00000000L #define BS_CENTER 0x00000300L #define DS_LOCALEDIT 0x20L #define ES_READONLY 0x0800L // идентификаторы кнопок #define IDC_BUTTON1 101 #define IDC_BUTTON2 102 #define IDC_BUTTON3 103 #define IDC_BUTTON4 104 DIAL1 DIALOG 0, 0, 170, 110 STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_3DLOOK CAPTION "Пример простейшего калькулятора" FONT 8, "Arial" { CONTROL "", 1, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 9, 8, 128, 12 CONTROL "", 2, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 9, 27, 128, 12 CONTROL "", 3, "edit", ES_LEFT | WS_CHILD | ES_READONLY | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 9, 76, 127, 12 CONTROL "+", IDC_BUTTON1, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 11, 48, 15, 14 CONTROL "-", IDC_BUTTON2, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 34, 48, 15, 14 CONTROL "*", IDC_BUTTON3, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 48, 15, 14 CONTROL "/", IDC_BUTTON4, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 80, 48, 15, 14 } ; calc. inc ; константы ; сообшение приходит при закрытии окна WM_CLOSE equ 10h WM_INITDIALOG equ 110h WM_COMMAND equ 111h WM_GETTEXT equ 0Dh WM_SETTEXT equ 0Ch ; прототипы внешних процедур EXTERN ExitProcess:NEAR EXTERN GetModuleHandleA:NEAR EXTERN DialogBoxParamA:NEAR EXTERN EndDialog:NEAR EXTERN SendDlgItemMessageA:NEAR ; структуры ; структура сообщения MSGSTRUCT STRUC MSHWND DWORD ? MSMESSAGE DWORD ? MSWPARAM DWORD ? MSLPARAM DWORD ? MSTIME DWORD ? MSPT DWORD ? MSGSTRUCT ENDS ; модуль calc.asm .386P ; поская модель .MODEL FLAT, stdcall include calc.inc EXTERN sum:NEAR EXTERN su:NEAR EXTERN mu:NEAR EXTERN dii:NEAR PUBLIC MAIN1 ; директивы компоновщику для подключения библиотек includelib c:\tasm32\lib\import32.lib ;------------------------------------------------ ;сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' MSG MSGSTRUCT <?> HINST DD 0 ; дескриптор приложения PA DB "DIAL1",0 S1 DB 50 DUP (0) S2 DB 50 DUP (0) S DB 50 DUP (0) _DATA ENDS ; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' ; процедура, вызываемая из Си-модуля MAIN1 PROC ; получить дескриптор приложения PUSH 0 CALL GetModuleHandleA MOV [HINST], EAX ;------------------------------------------- PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA ;------------------------------------------- RET MAIN1 ENDP ; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10Н] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP,ESP ;------------------------------------------- CMP DWORD PTR [EBP+0CH],WM_CLOSE JNE L1 PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog MOV EAX,1 JMP FINISH L1: CMP DWORD PTR [EBP+0CH],WM_INITDIALOG JNE L2 ; здесь заполнить окна редактирования, если надо JMP FINISH L2: CMP DWORD PTR [EBP+0CH],WM_COMMAND JNE FINISH CMP WORD PTR [EBP+10H],101 JNE NO_SUM ; первое слагаемое PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; второе слагаемое PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; сумма PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL sum ; вывести сумму PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JMP FINISH NO_SUM: CMP WORD PTR [EBP+10H],102 JNE NO_SUB ; уменьшаемое PUSH OFFSET SI PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; вычитаемое PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; разность PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL su ; вычислить разность PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JMP FINISH ; NO_SUB: CMP WORD PTR [EBP+10H],103 JNE NO_MULT ; первый множитель PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; второй множитель PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; произведение PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL mu ; вывести произведение PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JMP FINISH ; NO_MULT: CMP WORD PTR [EBP+10H],104 JNE FINISH ; делимое PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; делитель PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; деление PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL dii ; вывести результат деления PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JNE FINISH FINISH: MOV EAX,0 POP EBP RET 16 WNDPROC ENDP _TEXT ENDS END