Вызов API функций. Достоинства и недостатки...
Новый метод вызова API.

Относится к версии SPF 3.75 (build 089).

Как организуется вызов API-функций в Форте?

    Если посмотреть spf_win_api.f, процедуры вызова API-CALL, _WNDPROC-CODE,
то механизм вызова следующий:
Анализ механизма API-CALL: 1) Сохраняем переменные Форт окружения: PUSH ESI PUSH EDI PUSH EBP 2) Выделяем область данных для вызова API: SUB ESP, # 60 MOV EDI, ESP MOV ESI, EBP MOV ECX, # 15 CLD REP MOVS DWORD MOV EBP, ESP Причем полагаем, что передаем в вызывающую процедуру не более 15 параметров... 3) Вызываем процедуру POP EAX \ адрес вызываемой процедуры лежал на верхушке стека данных Форта CALL EAX 4) Восстанавливаем стек возврата и переменные: MOV EBX, EBP SUB EBX, ESP MOV ESP, EBP ADD ESP, # 60 POP EBP SUB EBP, EBX SUB EBP, # 4 MOV [EBP], EAX POP EDI POP ESI Next Анализ механизма _WNDPROC-CODE: 1) выделяет в области стека блок данных для стека возвратов: MOV EBP, ESP SUB ESP, # #ST-RES 2) Фомируется ссылка на адрес возврата PUSH EBP MOV EBP, 4 [EAX] ( адрес возврата из CALLBACK ) 3) Находится слово для вызова и оно вызывается... MOV EAX, [EAX] ( адрес адреса форт-процедуры ) MOV EAX, [EAX] ... CALL EAX ... 4) Стек восстанавливается к исходному варианту и возврат: MOV ESP, EBP MOV EBP, 4 [EAX] \ сохраненный EBP MOV EAX, [EAX] \ адрес возврата из CALLBACK XCHG EAX, [ESP] RET В итоге получаем следующее Организация памяти: Стек: Windows параметры ... Стек данных (арифметический стек) <-- вершина стека ... резерв Стек возвратов адрес вовзрата <-- вершина стека возвратов ... ... Достоинства: 1) вызов получается простым; 2) на вершине передаваемые параметры; 3) на вершине стека всегда код возврата. Недостатки: 1) при каждом вызове API-функции приходится копировать параметры. Это очень долго. Некоторые функции, предоставляемые Windows становятся не эффективными (например UpperCase). (решение: нет) 2) Если в какой-либо DLL у одной из функций параметров окажется больше 15, то такая функция будет работать не верно, и (решение:) для исправления этой ситуации придется увеличивать кол-во передаваемых параметров, что существенно увеличит время на вызов ВСЕХ функций Windows. 3) Если я захочу оставить очень большое N чисел в стеке данных, это дело затрет адрес возврата из процедуры (например передача списком до нуля каких-нибудь данных). (решение: установить {#ST-RES} достаточно большим). Для решения недостатков предлагаю поменять механизм интеграции Форт'а: Карта памяти: Стек: Windows параметры адрес вовзрата Стек возвратов <-- вершина стека возвратов ... резерв Стек данных (арифметический стек) <-- вершина стека ... ... ; Процедура входа в Форт _WNDPROC-CODE_Enter: pop eax ; адрес адреса вызова слова push ebp push esi push edi lea ebp, [esp-{#ST-RES}] ; выделяем память под стек возвратов ; и устанавливаем указатель на вершину стека данных push ebp ; Указатель на вершину стека данных lea esi, [esp+16] mov edi, ebp push 5 ; переносим 5 параметров, навряд ли будет больше 4!!! ; можно увеличить кол-во, все равно делается 1 раз при входе... pop ecx rep movsd call dword ptr [eax] ; Процедура выхода из Форта mov eax, [ebp] ; возвращаемое значение из стека pop ebx ; было ebp sub ebx, ebp ; убрать n байт со стека (отрицательное) pop edi pop esi pop ebp pop edx ; адрес возврата sub esp, ebx jmp edx Вызов API: push esi, edi, ... ; еще все что угодно swap esp, ebp pop eax ; адрес переменной WINAPI: call dwp [eax] push eax ; возвращаем результат swap esp, ebp pop ... edi, esi ret Достоинства: 1) вызов остается простым; 2) на вершине стека всегда код возврата; 3) вызов значительно быстрее; 4) вызванная процедура может как угодно использовать стек вниз; 5) невозможно отлаживать прогу стандартными отладчиками (затирают стек данных). Недостатки: 1) невозможно отлаживать прогу стандартными отладчиками - затирают стек данных (решение: а может пусть так и будет - полезно?). 2) на вершине 5 передаваемых параметров (решение: их кол-во можно увеличить или ввести дополнительное слово, возвращающее адрес вершины параметров); 3) уровень вложенности процедур не может быть больше ~{#ST-RES}/4 (решение: установить {#ST-RES} достаточно большим). Остается непонятным, как Windows организует управление стеком при вызове новых callback функций (например CALLBACK WindowProc)? По идее это должно быть что-то типа NewStack:=ESP-Очень_Большое_N, а может даже создание нового стека в CreateThread???????? В любом случае надо бы все это попробовать, потестировать... Голосуйте... P.S. Если чего-то не учел,то VVVVVVVVVVVVV Гневные пожелания и не очень жду по e-mail: winforth@narod.ru(Ежу)