WIN-FORTH для минималистов (проект FOBOS)
Страница 1 из 1
WIN-FORTH для минималистов (проект FOBOS)
Знать, где ловушка,- это первый шаг к тому, чтобы избежать ее. Это похоже на поединок, на дуэль, только масштабы другие. Выпад внутри выпада, а тот - внутри третьего, один финт в другом... и так, кажется, до бесконечности. Нам надо распутать этот проклятый клубок. /Фр.Герберт, Дюна/
ОБЩИЕ МЕСТА:
1. Программирование на FORTH только тогда доставит тебе удовольствие, когда ты сам этот FORTH написал.
2. Объектно-ориентированное программирование - болезнь, а глядя с высот FORTH - болезнь детская. Поэтому, наглые попытки, например, популярного Win32FORTH заставить меня пользоваться оконными классами - провокация и вопиющее головотяпство.
3. За основу первого проекта Win32-программирования взят очень хороший учебник ICZELION'S WIN32 ASM TUTORIAL (см. Приложение). Просто переписываю примеры с языка ассемблера на FORTH.
Конечно, я понимаю, что безнадежно отстал от жизни. Уже давно "бродит по Европе" Win-64... Однако, что имею, то и пою.
Наверняка, где-то да наврал. Найдете ляпы - пишите.
Предыстория - ТЕМА #3, АБЗАЦ #9
ОБЩИЕ МЕСТА:
1. Программирование на FORTH только тогда доставит тебе удовольствие, когда ты сам этот FORTH написал.
2. Объектно-ориентированное программирование - болезнь, а глядя с высот FORTH - болезнь детская. Поэтому, наглые попытки, например, популярного Win32FORTH заставить меня пользоваться оконными классами - провокация и вопиющее головотяпство.
3. За основу первого проекта Win32-программирования взят очень хороший учебник ICZELION'S WIN32 ASM TUTORIAL (см. Приложение). Просто переписываю примеры с языка ассемблера на FORTH.
Конечно, я понимаю, что безнадежно отстал от жизни. Уже давно "бродит по Европе" Win-64... Однако, что имею, то и пою.
Наверняка, где-то да наврал. Найдете ляпы - пишите.
Предыстория - ТЕМА #3, АБЗАЦ #9
Последний раз редактировалось: Gudleifr (Пн Фев 10, 2020 2:00 pm), всего редактировалось 3 раз(а)
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ТРУДНОЕ РЕШЕНИЕ
Must Die (далее просто MD, синоним слова Windows) имеет мерзейшую привычку делить все функции на два класса: а) те, что с огромным числом параметров, и б) те, что с одним параметром - адресом структуры, в которую подобные же параметры упакованы. Как запомнить, где какой случай? Как избавиться от замусоривания области имен ненужными конструкциями? Не спасает даже объектно-ориентированный оптимизм... Если хочешь постоянно использовать подобные конструкции, инкапсуляция всей этой белиберды будет арвиважнейшей задачей. Первоначально, я же не утруждал себя задачей причесывания, но плодил монстров. Потом мне это надоело.
Действительно, в чем разница между случаями (а) и (б)? В рамках традиционного высокоуровневого программирования - огромная. А для FORTH? Стек, ведь,- тоже память. Зачем мучиться с размещением структур в памяти и именованием полей, если их можно выкладывать куда-то поле за полем? Хочется, конечно, не куда-то, а в стек, так проще. Что-то вроде нижеследующего:
: ВЫЗОВ SP@ >R РАЗМЕЩАТЕЛИ-СТРУКТУР ЗАПОЛНИТЕЛИ-СТЕКА WIN-ФУНКЦИЯ CALL R> SWAP >R SP! R> ;
В большинстве случаев, например, при регистрации классов и создании окон, РАЗМЕЩАТЕЛИ и ЗАПОЛНИТЕЛИ могут быть стандартными. Здесь на помощь приходит слово DOER (DEFER мне нравится меньше). Получается пирамида - [DOER-]слово, целиком создающее кадр стека, состоящее из [DOER-]слов задающих группы параметров, в свою очередь, состоящих из DOER-слов отдельных параметров. Например, так:
DOER РАМКА-ОКНА
MAKE РАМКА-ОКНА CW_USEDEFAULT DUP 2DUP ;
Как должны выглядеть РАЗМЕЩАТЕЛИ? Учитываем, что стек данных растет вниз:
DOER РАЗМЕЩАТЕЛЬ
MAKE РАЗМЕЩАТЕЛЬ ПОЛЕ-N ... ПОЛЕ-1 РАЗМЕР SP@ ;
Почему DOER? А вдруг, эта структура будет использоваться неоднократно и, следовательно, будет размещаться в более долговременной памяти.
ЭКРАН 1/3 РАЗМЕР-ОКНА \ изменит слово РАМКА-ОКНА (см.выше)
ОКНО \ вызовет слово РАМКА-ОКНА
Попытавшись провести это решение в жизнь, сразу столкнулся с тремя неприятностями:
1. существуют структуры, которые задом-наперед не заполнить (например, строго последовательные блоки ресурсов),
2. несмотря на обилие вызовов Win-API в программе, количество повторных вызовов очень мало; даже для внешне похожих фиговин (см. ниже) наборы вызываемых для их создания/обслуживания функций могут не иметь ничего общего (например, controls, оставшиеся Win32 в наследство от Win3.1, и controls, реализованные в comctl32.dll),
3. иногда, все-таки, существует потребность в хранении подобных структур и между вызовами Win-API.
Но, невзирая на.., процесс пошел, и появилось две типовые разновидности блоков программ: посвященные вызову какой-либо функции (или небольшой группы функций) и посвященные какому-либо популярному заполнителю.
***
См. еще - ТЕМА #31, АБЗАЦ #247
Must Die (далее просто MD, синоним слова Windows) имеет мерзейшую привычку делить все функции на два класса: а) те, что с огромным числом параметров, и б) те, что с одним параметром - адресом структуры, в которую подобные же параметры упакованы. Как запомнить, где какой случай? Как избавиться от замусоривания области имен ненужными конструкциями? Не спасает даже объектно-ориентированный оптимизм... Если хочешь постоянно использовать подобные конструкции, инкапсуляция всей этой белиберды будет арвиважнейшей задачей. Первоначально, я же не утруждал себя задачей причесывания, но плодил монстров. Потом мне это надоело.
Действительно, в чем разница между случаями (а) и (б)? В рамках традиционного высокоуровневого программирования - огромная. А для FORTH? Стек, ведь,- тоже память. Зачем мучиться с размещением структур в памяти и именованием полей, если их можно выкладывать куда-то поле за полем? Хочется, конечно, не куда-то, а в стек, так проще. Что-то вроде нижеследующего:
: ВЫЗОВ SP@ >R РАЗМЕЩАТЕЛИ-СТРУКТУР ЗАПОЛНИТЕЛИ-СТЕКА WIN-ФУНКЦИЯ CALL R> SWAP >R SP! R> ;
В большинстве случаев, например, при регистрации классов и создании окон, РАЗМЕЩАТЕЛИ и ЗАПОЛНИТЕЛИ могут быть стандартными. Здесь на помощь приходит слово DOER (DEFER мне нравится меньше). Получается пирамида - [DOER-]слово, целиком создающее кадр стека, состоящее из [DOER-]слов задающих группы параметров, в свою очередь, состоящих из DOER-слов отдельных параметров. Например, так:
DOER РАМКА-ОКНА
MAKE РАМКА-ОКНА CW_USEDEFAULT DUP 2DUP ;
Как должны выглядеть РАЗМЕЩАТЕЛИ? Учитываем, что стек данных растет вниз:
DOER РАЗМЕЩАТЕЛЬ
MAKE РАЗМЕЩАТЕЛЬ ПОЛЕ-N ... ПОЛЕ-1 РАЗМЕР SP@ ;
Почему DOER? А вдруг, эта структура будет использоваться неоднократно и, следовательно, будет размещаться в более долговременной памяти.
ЭКРАН 1/3 РАЗМЕР-ОКНА \ изменит слово РАМКА-ОКНА (см.выше)
ОКНО \ вызовет слово РАМКА-ОКНА
Попытавшись провести это решение в жизнь, сразу столкнулся с тремя неприятностями:
1. существуют структуры, которые задом-наперед не заполнить (например, строго последовательные блоки ресурсов),
2. несмотря на обилие вызовов Win-API в программе, количество повторных вызовов очень мало; даже для внешне похожих фиговин (см. ниже) наборы вызываемых для их создания/обслуживания функций могут не иметь ничего общего (например, controls, оставшиеся Win32 в наследство от Win3.1, и controls, реализованные в comctl32.dll),
3. иногда, все-таки, существует потребность в хранении подобных структур и между вызовами Win-API.
Но, невзирая на.., процесс пошел, и появилось две типовые разновидности блоков программ: посвященные вызову какой-либо функции (или небольшой группы функций) и посвященные какому-либо популярному заполнителю.
***
См. еще - ТЕМА #31, АБЗАЦ #247
Последний раз редактировалось: Gudleifr (Ср Апр 24, 2019 10:00 pm), всего редактировалось 1 раз(а)
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ОБ ОБРАБОТЧИКАХ СООБЩЕНИЙ
Первоначально, обработчики WIN-сообщений рекомендовалось строить на основе оператора выбора (switch), занимающего в коде несколько страниц. Стараниями Рея Дункана, Эндрю Шульмана и других не-МелкоГибких разработчиков на смену switch-у пришли таблицы указателей на функции. Код стал более читабельным и компактным. Новацию переняла и команда Билла (понятно, присвоив себе славу первооткрывателей). Очевидно, имея в своем распоряжении FORTH, можно попытаться улучшить и это решение, чем я и занялся. Заметив, что в больших WIN-проектах в зависимости от состояния программы изменяются и способы обработки сообщений, я решил придать схеме побольше гибкости. Вот, что получилось:
Алгоритм О. УНИВЕРСАЛЬНЫЙ ОБРАБОТЧИК СООБЩЕНИЙ (Поиск по дереву без возвратов).
Входной параметр: КОД сообщения.
Выходной параметр: результат обработки сообщения (в терминах Windows).
О1. [Защелка.] Если КОД равен ЭТАЛОНУ, перейти к шагу 2, иначе - к 5.
О2. [Лист?] Если обработчик конечный, перейти к шагу 3, иначе - к шагу 4.
О3. [Вернуть результат.] Выполнить обработчик, вернуть его результат. Закончить работу.
О4. [Подобработчик.] Получить новый КОД (из MSG или состояния процесса). Безвозвратно перейти к обработчику-СЫНУ.
О5. [Следующий?] Если обработчика-БРАТА нет - перейти к шагу 3, иначе - к 6.
O6. [Переход.] Безвозвратно перейти к обработчику-БРАТУ. []
Видно, что процедуры шагов О3 (собственно обработчик) и О4 (получение нового КОДА) никогда не требуются одновременно. Значит можно сэкономить место и хранить в узле либо одно, либо другое.
Типовая WIN-ситуация:
1-й уровень - КОД = message
если WM_COMMAND:
2-й уровень - КОД = lpar (различение сообщений меню и органов управления)
3-й уровень - КОД = wpar (ID меню или органа управления)
***
Оказалось, подобный механизм мне понадобился еще раньше - при распознавании чисел в ядре FORTH, поэтому я добавил в ядро новое слово - RECEPTING. Затем, обнаглев, реализовал подобным образом и разбор командной строки. Получилось, что я сделал не просто дерево разбора, а универсальный конечный автомат.
Первоначально, обработчики WIN-сообщений рекомендовалось строить на основе оператора выбора (switch), занимающего в коде несколько страниц. Стараниями Рея Дункана, Эндрю Шульмана и других не-МелкоГибких разработчиков на смену switch-у пришли таблицы указателей на функции. Код стал более читабельным и компактным. Новацию переняла и команда Билла (понятно, присвоив себе славу первооткрывателей). Очевидно, имея в своем распоряжении FORTH, можно попытаться улучшить и это решение, чем я и занялся. Заметив, что в больших WIN-проектах в зависимости от состояния программы изменяются и способы обработки сообщений, я решил придать схеме побольше гибкости. Вот, что получилось:
Алгоритм О. УНИВЕРСАЛЬНЫЙ ОБРАБОТЧИК СООБЩЕНИЙ (Поиск по дереву без возвратов).
Входной параметр: КОД сообщения.
Выходной параметр: результат обработки сообщения (в терминах Windows).
О1. [Защелка.] Если КОД равен ЭТАЛОНУ, перейти к шагу 2, иначе - к 5.
О2. [Лист?] Если обработчик конечный, перейти к шагу 3, иначе - к шагу 4.
О3. [Вернуть результат.] Выполнить обработчик, вернуть его результат. Закончить работу.
О4. [Подобработчик.] Получить новый КОД (из MSG или состояния процесса). Безвозвратно перейти к обработчику-СЫНУ.
О5. [Следующий?] Если обработчика-БРАТА нет - перейти к шагу 3, иначе - к 6.
O6. [Переход.] Безвозвратно перейти к обработчику-БРАТУ. []
Видно, что процедуры шагов О3 (собственно обработчик) и О4 (получение нового КОДА) никогда не требуются одновременно. Значит можно сэкономить место и хранить в узле либо одно, либо другое.
Типовая WIN-ситуация:
1-й уровень - КОД = message
если WM_COMMAND:
2-й уровень - КОД = lpar (различение сообщений меню и органов управления)
3-й уровень - КОД = wpar (ID меню или органа управления)
***
Оказалось, подобный механизм мне понадобился еще раньше - при распознавании чисел в ядре FORTH, поэтому я добавил в ядро новое слово - RECEPTING. Затем, обнаглев, реализовал подобным образом и разбор командной строки. Получилось, что я сделал не просто дерево разбора, а универсальный конечный автомат.
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ТРЕХФИГОВОЕ ПРОКЛЯТИЕ MUST DIE
В Windows каждая фиговина должна быть описана трижды - а) как фиговина визуальная (размещение на экране, цвет и т.п.), б) как фиговина, что-то делающая (обработчик событий от этой фиговины), в) как фиговина, вызываемая по какому-то сообщению (привязка обработчика к сообщению и регистрация этого факта в функции обработки сообщений). Более того, фиговины должны связываться не только деревом обработки сообщений, но и сетью передач фокуса (по Tab), и матрицей Drag&Drop-ов...
Проблема была настолько удачно (конечно, за счет упрощения) решена в Visual Basic (и его Borland- и MS-потомках), что большинство современных программистов уверено, что виртуальные Events и Properties действительно имеют отношение к тому, что у Windows внутри.
С этой проблемой я бороться не стал (пока?). Хотя, кое-где удалось совместить все три описания.
В Windows каждая фиговина должна быть описана трижды - а) как фиговина визуальная (размещение на экране, цвет и т.п.), б) как фиговина, что-то делающая (обработчик событий от этой фиговины), в) как фиговина, вызываемая по какому-то сообщению (привязка обработчика к сообщению и регистрация этого факта в функции обработки сообщений). Более того, фиговины должны связываться не только деревом обработки сообщений, но и сетью передач фокуса (по Tab), и матрицей Drag&Drop-ов...
Проблема была настолько удачно (конечно, за счет упрощения) решена в Visual Basic (и его Borland- и MS-потомках), что большинство современных программистов уверено, что виртуальные Events и Properties действительно имеют отношение к тому, что у Windows внутри.
С этой проблемой я бороться не стал (пока?). Хотя, кое-где удалось совместить все три описания.
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ДВА ЗАМЕЧАНИЯ О КОНСТАНТАХ
Как общеизвестно, MD-API просто перегружен константами: почти каждая из API-функций имеет связанное семейство констант, а то и больше (выбор подфункции, режимы вызова, типовые значения операндов...). Я не стал полностью копировать windows.inc внутрь программы, более того, отказался даже от именования тех констант, которые используются в примерах (за исключением встречающихся неоднократно). Вместо этого, я при описании заполнителей стека указываю из какого семейства берутся константы.
***
Второе замечание касается большого класса однократно рассчитываемых, но многократно используемых значений. Они встречаются в MD-API столь часто, что я ввел слова для их определения:
( иниц.значение) WIN-CONST: слово расчет WIN-CONST;
( нов.иниц.значение) WIN-CONST! слово
Первая конструкция определяет способ расчета такой "константы", который будет выполнен при первом к ней обращении, вторая - дает возможность перерасчета "константы".
Подобный механизм использован и для обращения к API-функциям. При первом обращении происходит связывание и вызов, при последующих - только вызов по уже определенному адресу.
Как общеизвестно, MD-API просто перегружен константами: почти каждая из API-функций имеет связанное семейство констант, а то и больше (выбор подфункции, режимы вызова, типовые значения операндов...). Я не стал полностью копировать windows.inc внутрь программы, более того, отказался даже от именования тех констант, которые используются в примерах (за исключением встречающихся неоднократно). Вместо этого, я при описании заполнителей стека указываю из какого семейства берутся константы.
***
Второе замечание касается большого класса однократно рассчитываемых, но многократно используемых значений. Они встречаются в MD-API столь часто, что я ввел слова для их определения:
( иниц.значение) WIN-CONST: слово расчет WIN-CONST;
( нов.иниц.значение) WIN-CONST! слово
Первая конструкция определяет способ расчета такой "константы", который будет выполнен при первом к ней обращении, вторая - дает возможность перерасчета "константы".
Подобный механизм использован и для обращения к API-функциям. При первом обращении происходит связывание и вызов, при последующих - только вызов по уже определенному адресу.
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
СПИСОК ПРИМЕРОВ УЧЕБНИКА
1. THE BASICS
2. MESSAGEBOX -- удивительно, скольким программам такой MustDie-ности было бы вполне достаточно
3. A SIMPLE WINDOW
4. PAINTING WITH TEXT
5. MORE ABOUT TEXT
6. KEYBOARD INPUT
7. MOUSE INPUT
8. MENU
9. CHILD WINDOW CONTROLS
10. DIALOG BOX AS MAIN WINDOW -- здесь и далее: назначение многих ключей в ресурсе диалога так и остались невыясненными
11. MORE ABOUT DIALOG BOX
12. MEMORY MANAGEMENT AND FILE I/O
13. MEMORY MAPPED FILES
14. PROCESS
15. MULTITHREADING PROGRAMMING
16. EVENT OBJECT
17. DYNAMIC LINK LIBRARIES
18. COMMON CONTROLS
19. TREE VIEW CONTROL -- это нельзя понять, это нужно запомнить!
20. WINDOW SUBCLASSING
21. PIPE
22. SUPERCLASSING
23. TRAY ICON
24. WINDOWS HOOKS -- немного подправил ошибки
25. SIMPLE BITMAP
26. SPLASH SCREEN
27. TOOLTIP CONTROL
28. WIN32 DEBUG API. PART 1
29. WIN32 DEBUG API. PART 2 -- вторая часть этого и следующий пример вызывают справедливое недоумение некоторых антивирусов
30. WIN32 DEBUG API. PART 3 -- глючит, как и исходный пример, под некоторыми версиями MD?, процессорами..? Ошибка, в принципе, известна и описана в MD-документации.
31. LISTVIEW CONTROL -- славный продолжатель дела примера #19, к тому же подглючивает, как и исходный пример: нет пересчета размещения списка при изменении размера окна, и неочевидна реакция на первый doubleclick, если он попадает на поле размера файла
32. MULTIPLE DOCUMENT INTERFACE (MDI) -- Пирамиды, Великая Стена, "Ямато"? Фигушки! MDI!
33. RICHEDIT CONTROL. BASICS -- пока не готово
34. RICHEDIT CONTROL. MORE TEXT OPERATIONS -- пока не готово
35. RICHEDIT CONTROL. SYNTAX HILIGHTING -- пока не готово
Если кому уж совсем нечего делать, он может переписать в подобном ключе другие примеры из masm32 или книги Дж.Рихтера "Создание эффективных WIN32-приложений". Я не столько пытался создать учебник, сколько тестировал FOBOS.
ПОПУТНЫЕ ЗАМЕТКИ
Понятно, пришлось отказаться от статической подгрузки ресурсов и библиотек, поэтому некоторые варианты примеров опущены.
***
Номера сообщений и controls, а так же экранные сообщения и заголовки могут отличаться от приведенных в учебнике. Мне просто лень было их все отслеживать.
***
Куда делась компактность FORTH? 50% шитого кода - просто мусор (т.к. 16-разрядов было бы вполне достаточно). С ностальгией вспоминаю те времена, когда под код отводилось 64 килобайта. При грамотной организации процессов этого и сейчас было бы достаточно для написания ЛЮБОЙ программы.
***
Взяв ассемблер из старой DOS-версии FOBOS, я нашел в нем кучу ошибок. А ведь работало же! Потом заметил, что половина из них "не баги, но фичи", т.е. не так уж все было и неправильно.
***
Для работы всех примеров нет потребности в реализации большинства слов стандарта ANSI 94. Так, я до сих пор так и не ввел слово для операции умножения. Придется создавать для стандарта отдельный текстовый файл.
***
Черт, опять застрял на 33 примере: желание все сломать и начать заново, кажется просто неодолимым. Думаю, в течение недели (писано еще в конце 2009 года) я его все-таки "победю" и "раздувать мировой пожар" начну только после завершения 35-го примера.
1. THE BASICS
2. MESSAGEBOX -- удивительно, скольким программам такой MustDie-ности было бы вполне достаточно
3. A SIMPLE WINDOW
4. PAINTING WITH TEXT
5. MORE ABOUT TEXT
6. KEYBOARD INPUT
7. MOUSE INPUT
8. MENU
9. CHILD WINDOW CONTROLS
10. DIALOG BOX AS MAIN WINDOW -- здесь и далее: назначение многих ключей в ресурсе диалога так и остались невыясненными
11. MORE ABOUT DIALOG BOX
12. MEMORY MANAGEMENT AND FILE I/O
13. MEMORY MAPPED FILES
14. PROCESS
15. MULTITHREADING PROGRAMMING
16. EVENT OBJECT
17. DYNAMIC LINK LIBRARIES
18. COMMON CONTROLS
19. TREE VIEW CONTROL -- это нельзя понять, это нужно запомнить!
20. WINDOW SUBCLASSING
21. PIPE
22. SUPERCLASSING
23. TRAY ICON
24. WINDOWS HOOKS -- немного подправил ошибки
25. SIMPLE BITMAP
26. SPLASH SCREEN
27. TOOLTIP CONTROL
28. WIN32 DEBUG API. PART 1
29. WIN32 DEBUG API. PART 2 -- вторая часть этого и следующий пример вызывают справедливое недоумение некоторых антивирусов
30. WIN32 DEBUG API. PART 3 -- глючит, как и исходный пример, под некоторыми версиями MD?, процессорами..? Ошибка, в принципе, известна и описана в MD-документации.
31. LISTVIEW CONTROL -- славный продолжатель дела примера #19, к тому же подглючивает, как и исходный пример: нет пересчета размещения списка при изменении размера окна, и неочевидна реакция на первый doubleclick, если он попадает на поле размера файла
32. MULTIPLE DOCUMENT INTERFACE (MDI) -- Пирамиды, Великая Стена, "Ямато"? Фигушки! MDI!
33. RICHEDIT CONTROL. BASICS -- пока не готово
34. RICHEDIT CONTROL. MORE TEXT OPERATIONS -- пока не готово
35. RICHEDIT CONTROL. SYNTAX HILIGHTING -- пока не готово
Если кому уж совсем нечего делать, он может переписать в подобном ключе другие примеры из masm32 или книги Дж.Рихтера "Создание эффективных WIN32-приложений". Я не столько пытался создать учебник, сколько тестировал FOBOS.
ПОПУТНЫЕ ЗАМЕТКИ
Понятно, пришлось отказаться от статической подгрузки ресурсов и библиотек, поэтому некоторые варианты примеров опущены.
***
Номера сообщений и controls, а так же экранные сообщения и заголовки могут отличаться от приведенных в учебнике. Мне просто лень было их все отслеживать.
***
Куда делась компактность FORTH? 50% шитого кода - просто мусор (т.к. 16-разрядов было бы вполне достаточно). С ностальгией вспоминаю те времена, когда под код отводилось 64 килобайта. При грамотной организации процессов этого и сейчас было бы достаточно для написания ЛЮБОЙ программы.
***
Взяв ассемблер из старой DOS-версии FOBOS, я нашел в нем кучу ошибок. А ведь работало же! Потом заметил, что половина из них "не баги, но фичи", т.е. не так уж все было и неправильно.
***
Для работы всех примеров нет потребности в реализации большинства слов стандарта ANSI 94. Так, я до сих пор так и не ввел слово для операции умножения. Придется создавать для стандарта отдельный текстовый файл.
***
Черт, опять застрял на 33 примере: желание все сломать и начать заново, кажется просто неодолимым. Думаю, в течение недели (писано еще в конце 2009 года) я его все-таки "победю" и "раздувать мировой пожар" начну только после завершения 35-го примера.
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
EXE, DLL, ПРОЦЕССЫ И ПОТОКИ
Не буду вспоминать всю историю Must Die, но только напомню, что изначально планировалось плодить под него исключительно маленькие, однооконные приложения, свободно обменивающиеся данными. Только появление первого MDI-монстра - MS Excell - вернуло все на старые DOS-овские рельсы: "Если Вы хотите многозадачности, значит Вы должны ее поддерживать внутри своего приложения!"
***
Проблему EXE я, допустим, победил, вынеся все, что можно в текстовый файл. Конечно, у Вас остается возможность и дальнейшего вылизывания ядра (при наличии masm32). Для сборки использовал команды (masm32 v.6.14):
\masm32\bin\ml /c /coff g2.asm
\masm32\bin\Link /SUBSYSTEM:WINDOWS /STACK:1048576,65536 /section:.text,RWE g2.obj
Для DLL (см. ниже) - соответственно:
\masm32\bin\ml /c /coff g4.asm
\masm32\bin\Link /SUBSYSTEM:WINDOWS /DLL /DEF:g4.def /section:.text,RWE /section:.bss,RWS g4.obj
Где файл g4.def состоит из 4 строк:
LIBRARY g4
EXPORTS
DLLEXE
DLLCALL
***
ПРОЦЕССЫ? Пожалуйста. Запускай то же ядро, только с другим текстовым файлом. (Сейчас алгоритм следующий - FOBOS открывает текстовый файл (расширение .txt) с тем же именем, что и исполняемый или (в случае наличия в командной строке имени файла) любой указанный (но тоже с расширением .txt).)
***
ПОТОКИ? См. как это сделано в примерах 15-16. Нужно ли это? На мой взгляд, сама идея потоков - следствие недоработки операционной системы. Есть процессы. Если бы они были реализованы по-человечески, то покрывали бы все потребности распараллеливания вычислений, плюс снимали бы с программиста всю головную боль по их изоляции друг от друга. А так мы вынуждены сами организовывать многозадачность и ломать голову над обеспечением синхронизации, сохранения критических данных и прочего.
***
DLL? Тут две проблемы: практическая и философская.
С точки зрения практики, это вопрос о повторном использовании кода. Выиграть в размере программы, используя в нескольких процессах общий кусок кода? Изолировать пространство процедур от пространства программ? Обеспечить совместимость разных программ используя стандартный интерфейс? На протяжении всей истории DOS-Windows принимались самые разные решения, и сейчас, наверное, уже никого не волнует, как это все работает. И, более того, когда программисту лень разбираться в существующих стандартах, он не колеблясь, придумывает собственные, называя их оверлеями, расширениями и т.д.
А все зло - от нерешенности второй проблемы - философской. Что есть подпрограмма? Часть кода, пригодная для повторного решения задач, схожих с текущей? Или - расширение операционной системы для создания цепочки все более мощных машин-бусин (опять Дейкстра)? Каждый решает по-своему. Отсюда и разнобой. Тем более, что приходится отталкиваться от произвольно принимаемых Биллом решений.
Как реализовать DLL в рамках текущего проекта? Так же, как реализовали EXE - ядро и текстовый довесок. Текстовый довесок интерпретируется в ф-ии Dll-main (при подключении к процессу). Вторая точка входа - итерпретация переданного слова (DLLEXE). Способ вызова: заполнить стек параметрами, добавить туда же строку со счетчиком - нужное библиотечное слово, найти адрес DLLEXE и EXECUTE его.
(Для универсальности снабдил DLL-заготовку 64K-блоком разделяемых параметров, и 1K пустым местом под вторую точку входа (DLLCALL). Как это использовать, видно в примере про Hook-исы).
Не буду вспоминать всю историю Must Die, но только напомню, что изначально планировалось плодить под него исключительно маленькие, однооконные приложения, свободно обменивающиеся данными. Только появление первого MDI-монстра - MS Excell - вернуло все на старые DOS-овские рельсы: "Если Вы хотите многозадачности, значит Вы должны ее поддерживать внутри своего приложения!"
***
Проблему EXE я, допустим, победил, вынеся все, что можно в текстовый файл. Конечно, у Вас остается возможность и дальнейшего вылизывания ядра (при наличии masm32). Для сборки использовал команды (masm32 v.6.14):
\masm32\bin\ml /c /coff g2.asm
\masm32\bin\Link /SUBSYSTEM:WINDOWS /STACK:1048576,65536 /section:.text,RWE g2.obj
Для DLL (см. ниже) - соответственно:
\masm32\bin\ml /c /coff g4.asm
\masm32\bin\Link /SUBSYSTEM:WINDOWS /DLL /DEF:g4.def /section:.text,RWE /section:.bss,RWS g4.obj
Где файл g4.def состоит из 4 строк:
LIBRARY g4
EXPORTS
DLLEXE
DLLCALL
***
ПРОЦЕССЫ? Пожалуйста. Запускай то же ядро, только с другим текстовым файлом. (Сейчас алгоритм следующий - FOBOS открывает текстовый файл (расширение .txt) с тем же именем, что и исполняемый или (в случае наличия в командной строке имени файла) любой указанный (но тоже с расширением .txt).)
***
ПОТОКИ? См. как это сделано в примерах 15-16. Нужно ли это? На мой взгляд, сама идея потоков - следствие недоработки операционной системы. Есть процессы. Если бы они были реализованы по-человечески, то покрывали бы все потребности распараллеливания вычислений, плюс снимали бы с программиста всю головную боль по их изоляции друг от друга. А так мы вынуждены сами организовывать многозадачность и ломать голову над обеспечением синхронизации, сохранения критических данных и прочего.
***
DLL? Тут две проблемы: практическая и философская.
С точки зрения практики, это вопрос о повторном использовании кода. Выиграть в размере программы, используя в нескольких процессах общий кусок кода? Изолировать пространство процедур от пространства программ? Обеспечить совместимость разных программ используя стандартный интерфейс? На протяжении всей истории DOS-Windows принимались самые разные решения, и сейчас, наверное, уже никого не волнует, как это все работает. И, более того, когда программисту лень разбираться в существующих стандартах, он не колеблясь, придумывает собственные, называя их оверлеями, расширениями и т.д.
А все зло - от нерешенности второй проблемы - философской. Что есть подпрограмма? Часть кода, пригодная для повторного решения задач, схожих с текущей? Или - расширение операционной системы для создания цепочки все более мощных машин-бусин (опять Дейкстра)? Каждый решает по-своему. Отсюда и разнобой. Тем более, что приходится отталкиваться от произвольно принимаемых Биллом решений.
Как реализовать DLL в рамках текущего проекта? Так же, как реализовали EXE - ядро и текстовый довесок. Текстовый довесок интерпретируется в ф-ии Dll-main (при подключении к процессу). Вторая точка входа - итерпретация переданного слова (DLLEXE). Способ вызова: заполнить стек параметрами, добавить туда же строку со счетчиком - нужное библиотечное слово, найти адрес DLLEXE и EXECUTE его.
(Для универсальности снабдил DLL-заготовку 64K-блоком разделяемых параметров, и 1K пустым местом под вторую точку входа (DLLCALL). Как это использовать, видно в примере про Hook-исы).
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ЖАЛКИЙ БРЕД О ГРАФИЧЕСКОМ ИНТЕРФЕЙСЕ
Очевидно, что, кроме огромного запаса API-функций, -структур, -сообщений и -констант, программист вынужден выучить еще и некие API-парадигмы, малейший отход от которых приведет к немедленному краху интерфейса проекта. Попыток как-то упорядочить эти самые парадигмы не перечесть, но, грубо говоря, есть всего три варианта.
1. Попытка систематизировать все эти API-кубики "как есть", разрешив программисту самому собрать из них что-то полезное. В примерах применялся именно этот подход. Результат - плачевный. Всем понятно, что достигнуть тут хоть какой-то обозримости можно только за счет грубого упрощения - сведения всех (часто) используемых параметров в списки propertie-сов и event-ов.
2. "Игровой подход" - отрисовать красивый экран самому, классифицировать все области пространства на экране и "перемножить" на все возможные действия мышкой (клики, Dbl- и Right-клики, Move, Drag&Drop-ы...) и клавиатуры (по крайней мере, Shift, Alt и Ctrl), привязав к каждой клетке получившейся таблицы осмысленные API-парадигмы.
3. Подход, предложенный в "Комнатной модели",- привязать парадигмы к "желаниям" и "ожиданиям" пользователя, плюнув на "универсальность", вроде бы постулируемую Биллом.
Дальнейший бред на эту тему - ТЕМА #34.
Очевидно, что, кроме огромного запаса API-функций, -структур, -сообщений и -констант, программист вынужден выучить еще и некие API-парадигмы, малейший отход от которых приведет к немедленному краху интерфейса проекта. Попыток как-то упорядочить эти самые парадигмы не перечесть, но, грубо говоря, есть всего три варианта.
1. Попытка систематизировать все эти API-кубики "как есть", разрешив программисту самому собрать из них что-то полезное. В примерах применялся именно этот подход. Результат - плачевный. Всем понятно, что достигнуть тут хоть какой-то обозримости можно только за счет грубого упрощения - сведения всех (часто) используемых параметров в списки propertie-сов и event-ов.
2. "Игровой подход" - отрисовать красивый экран самому, классифицировать все области пространства на экране и "перемножить" на все возможные действия мышкой (клики, Dbl- и Right-клики, Move, Drag&Drop-ы...) и клавиатуры (по крайней мере, Shift, Alt и Ctrl), привязав к каждой клетке получившейся таблицы осмысленные API-парадигмы.
3. Подход, предложенный в "Комнатной модели",- привязать парадигмы к "желаниям" и "ожиданиям" пользователя, плюнув на "универсальность", вроде бы постулируемую Биллом.
Дальнейший бред на эту тему - ТЕМА #34.
Последний раз редактировалось: Gudleifr (Ср Апр 24, 2019 10:05 pm), всего редактировалось 1 раз(а)
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ЕЩЕ О ЦИКЛЕ ОБРАБОТКИ СООБЩЕНИЙ И КЛАССАХ ОКОН
Попытаюсь здесь изложить общие места, хотя бы для того, чтобы разобраться самому.
ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ. Он не нужен тем приложениям, весь интерфейс, которых обеспечивается
- обращениям к MessageBox (примеры 02, 17),
- диалоговыми окнами, созданными функцией DialogBoxIndirectParam (функция DialogBoxParam нам не интересна, т.к. требует статической подгрузки ресурсов) (примеры 10A, 24, 27),
- стандартными диалогами (создаваемыми, например, функцией GetOpenFileName) (пример 28, 30) или
- их комбинацией.
В противном случае, на все время существования окна приложения основная ветвь управления крутится в этом самом цикле. (Правда, некоторые сообщения окну умудряются "проскочить", даже, если никакой цикл обработки еще не работает.) Финты вроде того, чтобы уничтожить окно, выйти из цикла, что-то сделать, создать новое окно и войти в новый цикл, не встречаются. Полная форма цикла обработки сообщения выглядит упрощенно так:
Алгоритм Ц. ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ ПРИЛОЖЕНИЯ (Один на приложение).
Входные параметры: сложная система очередей сообщений Windows.
Выходной параметр: wParam последнего сообщения.
Внутренняя переменная: блок сообщений (структура MSG), состоящий из полей: hwnd - окно, которому адресовано сообщение, message - номер сообщения, wParam и lParam - параметры, time и pt (x и y) - временные и пространственные координаты сообщения.
Ц1. [Получение.] Выполнить GetMessage, если эта функция вернула 0, перейти к шагу 6, иначе - к шагу 2.
Ц2. [Немодальные диалоги.] Для всех [открытых] немодальных диалогов (созданных функцией CreateDialogIndirectParam) выполнить функцию IsDialogMessage, при получении первого ненулевого результата перейти к шагу 1. Если все вызовы вернули 0, перейти к шагу 3. (Обойтись без цикла, определяя нужный диалог по самому сообщению, очень сложно, т.к. диалог обрабатывает не только "свои" сообщения, но и сообщения своих дочерних окон.)
Ц3. [Акселераторы.] Выполнить TranslateAccelerator для текущей таблицы акселераторов (конечно, только если таковая имеется). (Вопрос о наличии нескольких таблиц акселераторов нигде не рассматривается.) В случае ненулевого результата перейти к шагу 1 (в этом случае генерируется новое сообщение, заменяющее старое), иначе - к шагу 4.
Ц4. [Трансляция.] Выполнить TranslateNessage, перейти к шагу 5.
Ц5. [Обработка.] Выполнить DispatchMessage, перейти к шагу 1.
Ц6. [Завершение.] Закончить работу, считая выходным результатом (который может использовать затем функция ExitProcess - завершение приложения) поле wParam. []
В простейшем случае шаги Ц2 и Ц3 обычно опускаются.
***
КЛАССЫ ОКОН. Типов окон в Windows очень много, хотя внутри системы все они описываются одинаковым набором параметров (параметры делятся на параметры класса окна и параметры самого окна - в лучших традициях объектно-ориентированного программирования). Отличаются окна друг от друга: во-первых, различными значениями этих самых параметров, в том числе, параметров, описывающих их (окон) взаимную зависимость; во-вторых, совершенно различными (для пользователя) способами создания окон; в-третьих, различиями (опять, только для пользователя) в управлении окнами (в первую очередь, выражающимися в виде их оконных функций).
Некоторые среды программирования, например фирмы Borland, вообще, абстрагируются от этих различий, предпочитая иметь дело только с окнами общего вида и controls (тоже, ведь, окна).
Еще одна сложность состоит в том, что ни в коем случае нельзя путать то, что рисуется на самом окне (фоновая картинка, текст) с дочерними окнами controls (кнопками, окнами редактирования и т.д.), размещаемыми в окне. Иногда этот вопрос сильно запутывается, например, в случае меню, но в этих случаях Win-API предлагает столько разнообразных функций, что разбираться в том "как все на самом деле" нет никакого резона.
Перечислю типы окон, встреченные в примерах.
Примечания:
* - запись вида "0 или результат функции", означает, "если оконная функция считает, что она полностью обработала сообщение, она возвращает 0, иначе - передает сообщение для обработки указанной функции".
** - суффикс Indirect появился у меня в силу того, что моя концепция минимального exe-ядра не позволяет загружать ресурсы напрямую в exe-файл.
*** - меню можно прописывать и в параметры класса и в параметры окна, но первый способ, как и в случае ресурсов, для меня оказался недоступен.
ФУНКЦИИ ЗАКРЫТИЯ ОКОН. Эти функции "размазаны" по дереву обработчика сообщений и отслеживать их затруднительно. Обычно используются три стандартных сообщения (WM_CLOSE, WM_DESTROY и WM_MDIDESTROY) и три функции (PostQuitMessage, DestroyWindow и EndDialog). Я понял это так:
1. функция PostQuitMessage вызывает завершение цикла обработчика сообщений и должна обязательно присутствовать в обязательном обработчике сообщения WM_DESTROY главного окна общего вида или немодальном диалоге, играющим его роль;
2. убить любое окно можно, послав ему сообщение WM_CLOSE;
3. обработчики сообщения WM_CLOSE обязательны для немодальных диалогов с родителем, модальных диалогов (в обоих случаях в них вызывается EndDialog) и дочернем окне MDI (оттуда надо послать сообщение WM_MDIDESTROY MDICLIENT родительского окна);
4. к посылке главному окну сообщения WM_DESTROY приводит функция DestroyWindow (и стандартный обработчик WM_CLOSE в DefWindowProc (?));
5. цепочка обработки сообщений, приводящая к вызову DestroyWindow или EndDialog, может довольно сильно петлять, например, в диалоге получение WM_CLOSE может приводить к передаче какого-то другого сообщения, и только обработка того приведет к вызову EndDialog;
6. вызывать DestroyWindow и EndDialog из любого места, где может понадобиться закрытие окна, или использовать дополнительное сообщение для перехода к тому единственному обработчику (обычно привязываемому к какому-либо "закрывающему" control), в котором стоит подобный вызов - дело вкуса.
***
Можно ли тут что-то FORTH-упростить? Могу только констатировать, что, тупо переписывая примеры учебника на FORTH, допустил ряд ошибок:
- забыл предусмотреть в слове, реализующем цикл обработки сообщений, дырки для встраивания обработки немодальных диалогов и таблиц акселераторов;
- не учел наличия большого числа оконных функций в сложных приложениях;
- не создал типовых слов для переопределения заполнителей при вызове функции CreateWindowEx и не применил к ним механизма восстанавливаемых ассемблеров, тоже для открытия/закрытия файлов;
- не предусмотрел механизмов для поддержки одновременного существования нескольких ресурсов меню и/или диалогов;
- не обрезал возможность различной маршрутизации сигналов закрытия окон путем введения пары-другой типовых слов.
- не привел все call-back функции к одному знаменателю.
Попытаюсь здесь изложить общие места, хотя бы для того, чтобы разобраться самому.
ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ. Он не нужен тем приложениям, весь интерфейс, которых обеспечивается
- обращениям к MessageBox (примеры 02, 17),
- диалоговыми окнами, созданными функцией DialogBoxIndirectParam (функция DialogBoxParam нам не интересна, т.к. требует статической подгрузки ресурсов) (примеры 10A, 24, 27),
- стандартными диалогами (создаваемыми, например, функцией GetOpenFileName) (пример 28, 30) или
- их комбинацией.
В противном случае, на все время существования окна приложения основная ветвь управления крутится в этом самом цикле. (Правда, некоторые сообщения окну умудряются "проскочить", даже, если никакой цикл обработки еще не работает.) Финты вроде того, чтобы уничтожить окно, выйти из цикла, что-то сделать, создать новое окно и войти в новый цикл, не встречаются. Полная форма цикла обработки сообщения выглядит упрощенно так:
Алгоритм Ц. ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ ПРИЛОЖЕНИЯ (Один на приложение).
Входные параметры: сложная система очередей сообщений Windows.
Выходной параметр: wParam последнего сообщения.
Внутренняя переменная: блок сообщений (структура MSG), состоящий из полей: hwnd - окно, которому адресовано сообщение, message - номер сообщения, wParam и lParam - параметры, time и pt (x и y) - временные и пространственные координаты сообщения.
Ц1. [Получение.] Выполнить GetMessage, если эта функция вернула 0, перейти к шагу 6, иначе - к шагу 2.
Ц2. [Немодальные диалоги.] Для всех [открытых] немодальных диалогов (созданных функцией CreateDialogIndirectParam) выполнить функцию IsDialogMessage, при получении первого ненулевого результата перейти к шагу 1. Если все вызовы вернули 0, перейти к шагу 3. (Обойтись без цикла, определяя нужный диалог по самому сообщению, очень сложно, т.к. диалог обрабатывает не только "свои" сообщения, но и сообщения своих дочерних окон.)
Ц3. [Акселераторы.] Выполнить TranslateAccelerator для текущей таблицы акселераторов (конечно, только если таковая имеется). (Вопрос о наличии нескольких таблиц акселераторов нигде не рассматривается.) В случае ненулевого результата перейти к шагу 1 (в этом случае генерируется новое сообщение, заменяющее старое), иначе - к шагу 4.
Ц4. [Трансляция.] Выполнить TranslateNessage, перейти к шагу 5.
Ц5. [Обработка.] Выполнить DispatchMessage, перейти к шагу 1.
Ц6. [Завершение.] Закончить работу, считая выходным результатом (который может использовать затем функция ExitProcess - завершение приложения) поле wParam. []
В простейшем случае шаги Ц2 и Ц3 обычно опускаются.
***
КЛАССЫ ОКОН. Типов окон в Windows очень много, хотя внутри системы все они описываются одинаковым набором параметров (параметры делятся на параметры класса окна и параметры самого окна - в лучших традициях объектно-ориентированного программирования). Отличаются окна друг от друга: во-первых, различными значениями этих самых параметров, в том числе, параметров, описывающих их (окон) взаимную зависимость; во-вторых, совершенно различными (для пользователя) способами создания окон; в-третьих, различиями (опять, только для пользователя) в управлении окнами (в первую очередь, выражающимися в виде их оконных функций).
Некоторые среды программирования, например фирмы Borland, вообще, абстрагируются от этих различий, предпочитая иметь дело только с окнами общего вида и controls (тоже, ведь, окна).
Еще одна сложность состоит в том, что ни в коем случае нельзя путать то, что рисуется на самом окне (фоновая картинка, текст) с дочерними окнами controls (кнопками, окнами редактирования и т.д.), размещаемыми в окне. Иногда этот вопрос сильно запутывается, например, в случае меню, но в этих случаях Win-API предлагает столько разнообразных функций, что разбираться в том "как все на самом деле" нет никакого резона.
Перечислю типы окон, встреченные в примерах.
Тип | Создание | Что должна вернуть оконная функция (и нужна ли она) | Примечания | ||
Класс | Окно | # примера | Замечания | ||
Стандартные диалоги | - | MessageBox, GetOpenFileName и т.п. | - | 2, 11B, 23 | встречаются и нетривиальные случаи, например, иконка на панели задач |
Окно общего вида | RegisterClassEx | CreateWindowEx | 0 или результат DefWindowProc * | 3-8, 25 | во всех примерах - только одно на приложение, обычно имеет меню *** |
Control | - | CreateWindowEx или специальные функции | - | 9, 18, 19, 27, 31, 32 | controls неявно делятся на две группы - вставляемые преимущественно в окна общего вида (иногда, даже, бывают сильно нетривиальными и/или невидимыми) и используемые преимущественно в диалоговых окнах (обычно простые) |
Немодальный диалог в роли окна общего вида | RegisterClassEx | CreateDialogIndirectParam ** | 0 или результат DefWindowProc | 10 | такой диалог очень похож на обычное окно и обычно имеет меню |
Модальный диалог | - | DialogBoxIndirectParam | 1 - в случае, если сообщение обработано, 0 - в противном случае | 10A, 11A, 24 | если используется вместо обычного окна, обычно снабжается меню |
Немодальный диалог при живом родителе | - | CreateDialogIndirectParam | 1 - в случае, если сообщение обработано, 0 - в противном случае | 11 | - |
Субкласс | - | CreateWindowEx | 0 или результат CallWindowProc | 20 | изготовляются из обычных сontrols подменой оконной функции |
Суперкласс | RegisterClassEx | CreateWindowEx | 0 или результат CallWindowProc | 22 | изготовляются из обычных сontrols подменой оконной функции, но не в параметрах окна, а в параметрах класса |
MDI фрейм | RegisterClassEx | CreateWindowEx | 0 или результат DefFrameProc | 32 | изготовляется из окна общего вида, созданием в нем специального control MDICLIENT |
MDI дочернее окно | RegisterClassEx | посылка сообщения родительскому MDICLIENT | 0 или результат DefMDIChildProc | 32 | практически, окно общего вида, только меню "делегируется" родительскому окну |
* - запись вида "0 или результат функции", означает, "если оконная функция считает, что она полностью обработала сообщение, она возвращает 0, иначе - передает сообщение для обработки указанной функции".
** - суффикс Indirect появился у меня в силу того, что моя концепция минимального exe-ядра не позволяет загружать ресурсы напрямую в exe-файл.
*** - меню можно прописывать и в параметры класса и в параметры окна, но первый способ, как и в случае ресурсов, для меня оказался недоступен.
ФУНКЦИИ ЗАКРЫТИЯ ОКОН. Эти функции "размазаны" по дереву обработчика сообщений и отслеживать их затруднительно. Обычно используются три стандартных сообщения (WM_CLOSE, WM_DESTROY и WM_MDIDESTROY) и три функции (PostQuitMessage, DestroyWindow и EndDialog). Я понял это так:
1. функция PostQuitMessage вызывает завершение цикла обработчика сообщений и должна обязательно присутствовать в обязательном обработчике сообщения WM_DESTROY главного окна общего вида или немодальном диалоге, играющим его роль;
2. убить любое окно можно, послав ему сообщение WM_CLOSE;
3. обработчики сообщения WM_CLOSE обязательны для немодальных диалогов с родителем, модальных диалогов (в обоих случаях в них вызывается EndDialog) и дочернем окне MDI (оттуда надо послать сообщение WM_MDIDESTROY MDICLIENT родительского окна);
4. к посылке главному окну сообщения WM_DESTROY приводит функция DestroyWindow (и стандартный обработчик WM_CLOSE в DefWindowProc (?));
5. цепочка обработки сообщений, приводящая к вызову DestroyWindow или EndDialog, может довольно сильно петлять, например, в диалоге получение WM_CLOSE может приводить к передаче какого-то другого сообщения, и только обработка того приведет к вызову EndDialog;
6. вызывать DestroyWindow и EndDialog из любого места, где может понадобиться закрытие окна, или использовать дополнительное сообщение для перехода к тому единственному обработчику (обычно привязываемому к какому-либо "закрывающему" control), в котором стоит подобный вызов - дело вкуса.
***
Можно ли тут что-то FORTH-упростить? Могу только констатировать, что, тупо переписывая примеры учебника на FORTH, допустил ряд ошибок:
- забыл предусмотреть в слове, реализующем цикл обработки сообщений, дырки для встраивания обработки немодальных диалогов и таблиц акселераторов;
- не учел наличия большого числа оконных функций в сложных приложениях;
- не создал типовых слов для переопределения заполнителей при вызове функции CreateWindowEx и не применил к ним механизма восстанавливаемых ассемблеров, тоже для открытия/закрытия файлов;
- не предусмотрел механизмов для поддержки одновременного существования нескольких ресурсов меню и/или диалогов;
- не обрезал возможность различной маршрутизации сигналов закрытия окон путем введения пары-другой типовых слов.
- не привел все call-back функции к одному знаменателю.
Последний раз редактировалось: Gudleifr (Вт Окт 24, 2017 8:23 pm), всего редактировалось 1 раз(а)
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
РАБОТА НАД ОШИБКАМИ
Пожалуй, полгода я потратил на тщетные попытки как-то рационализировать интерфейсы своих Windows-программ, забросив дописывание примеров, точнее, лишь внося в них какие-то, вроде бы, поясняющие и упрощающие поправки. Постепенно я пришел к пониманию, что ничего из этого не выйдет по очень простой причине - я строю замок на песке. Попытка создать простой и понятный интерфейс "программа-пользователь" заранее была провальной, т.к. потребный для этого частный интерфейс "программа-Windows" так и остался набором разнородных рекомендаций и мутных правил.
Когда-то давным-давно я задался целью создать кнопочку в окне общего вида. О Windows я тогда мало что знал и честно полез в его справочную систему. Практически сразу нашел: "Чтобы создать кнопку в диалоговом окне, в файле ресурсов...". С настойчивостью героя "Улитки на склоне", я продолжил поиски. Нашел: "Кнопка в окне общего вида? Это совсем другое дело! Вот, если Вам нужна кнопка в диалоговом окне, то в файле ресурсов..." Так и сейчас, глядя на свою свалку примеров, вижу только несколько кухонных рецептов, но никакого очевидного практически пригодного способа приготовить на Must Die именно то, что хочется.
Как я писал примеры? Брал очередной-пример из asm-учебника и тупо переписывал на FORTH, заменяя макросы и более-менее общие куски FORTH-словами. Когда встречал Win-константу, лез в masm-файл windows.inc и выдергивал оттуда ее численное определение. Когда встречал вызов Win-функцию, вызывал справочник MSDN (занимающий на копьютере несколько гигабайт) и проверял, в какой dll-библиотеке она "живет", имеет ли ASCII-суффикс, как вызывается и что возвращает... Получилось, что для нормальной работы с моим набором примеров необходимы эти самые справочники, ведь именно в них указано, как видоизменить пример для получения чего-то путного.
Сравнивая любой из примеров с программой, написанной в каком-нибудь визуальном обезьяннике, можно видеть следующие куски:
1. Запускающая часть. В примере - обычно вызов общей парадигмы регистрации и отображения универсального окна, определенной в третьем примере. В Borland-программе, ее, например, обычно вообще не видно, а в MS Visual C++ она спрятана в кусках, имеющих страшные комментарии "Не влезай - убьет!" Здесь ситуация обратная детским кубикам, где для построения чего-либо достаточно чертежа - соединение кубиков друг с другом очевидно. MD-программа - это, скорее, красивый розовый домик, в разных комнатах которого надо расставлять мебель, селить Барби и Кена (и не дай бог перепутать).
2. Определения необходимых Win-API сущностей. В примере - жалкие огрызки бесконечных Win-справочников, а в обезъянниках - гиперссылки на эти самые справочники. По идее, это каталог кубиков (прайс-лист какой-нибудь "икеи" в Барби-модели).
3. Win-парадигмы. Вот тут мои примеры немного симпатичнее страшно выглядящих asm- и C-вызовов, т.к. мне удалось хоть как-то засунуть общие куски в универсальные слова. Т.е. хотя бы на этом уровне удалось загнать внутрь "кубиков" хоть немного MD-требухи.
4. Смысловая часть примеров. Ни у меня, ни в обезьянниках ее практически невозможно отличить от (3). А ведь здесь было бы самое место чертежу.
А применимо ли вообще понятие "кубика" к программированию? Исторически это очень близко к машинам-бусинам Дейкстры и конструкциям структурного программирования. Объектно-ориентированное программирование - это, скорее, уже отход от данной схемы, т.к. кубики стали в большинстве случаев нестыкуемыми. Т.о. налицо следующие проблемы.
1. Необходим какой-либо справочник, пусть убогий для того, чтобы обрисовать хотя бы примерную область применения показанного в примере API-средства.
2. Необходимо как-то разграничить примененные в примере виды данных и программные структуры на те, которыми можно "поиграть" для модификации примера (цвет фона, позиция Control, текст приглашения...), те, которые важны для примера (стиль окна, обрабатываемые сообщения...), и те, которые должны выступать в жесткой связке (открывающие и закрывающие функции, имена классов, handlers...).
Вводить для каждого примера базу данных, содержащую в виде доменов полные множества внешних параметров? Мол, в примере, я использовал именно этот кортеж входных данных, но заполнив его другими допустимыми значениями, я получу пример с немного другой функциональностью. Правда, это будет уже не база данных, а, скорее, база знаний, т.к. в ней придется хранить и мощный фильтр недопустимых кортежей, составленных вроде бы из вполне законных значений.
Пожалуй, полгода я потратил на тщетные попытки как-то рационализировать интерфейсы своих Windows-программ, забросив дописывание примеров, точнее, лишь внося в них какие-то, вроде бы, поясняющие и упрощающие поправки. Постепенно я пришел к пониманию, что ничего из этого не выйдет по очень простой причине - я строю замок на песке. Попытка создать простой и понятный интерфейс "программа-пользователь" заранее была провальной, т.к. потребный для этого частный интерфейс "программа-Windows" так и остался набором разнородных рекомендаций и мутных правил.
Когда-то давным-давно я задался целью создать кнопочку в окне общего вида. О Windows я тогда мало что знал и честно полез в его справочную систему. Практически сразу нашел: "Чтобы создать кнопку в диалоговом окне, в файле ресурсов...". С настойчивостью героя "Улитки на склоне", я продолжил поиски. Нашел: "Кнопка в окне общего вида? Это совсем другое дело! Вот, если Вам нужна кнопка в диалоговом окне, то в файле ресурсов..." Так и сейчас, глядя на свою свалку примеров, вижу только несколько кухонных рецептов, но никакого очевидного практически пригодного способа приготовить на Must Die именно то, что хочется.
Как я писал примеры? Брал очередной-пример из asm-учебника и тупо переписывал на FORTH, заменяя макросы и более-менее общие куски FORTH-словами. Когда встречал Win-константу, лез в masm-файл windows.inc и выдергивал оттуда ее численное определение. Когда встречал вызов Win-функцию, вызывал справочник MSDN (занимающий на копьютере несколько гигабайт) и проверял, в какой dll-библиотеке она "живет", имеет ли ASCII-суффикс, как вызывается и что возвращает... Получилось, что для нормальной работы с моим набором примеров необходимы эти самые справочники, ведь именно в них указано, как видоизменить пример для получения чего-то путного.
Сравнивая любой из примеров с программой, написанной в каком-нибудь визуальном обезьяннике, можно видеть следующие куски:
1. Запускающая часть. В примере - обычно вызов общей парадигмы регистрации и отображения универсального окна, определенной в третьем примере. В Borland-программе, ее, например, обычно вообще не видно, а в MS Visual C++ она спрятана в кусках, имеющих страшные комментарии "Не влезай - убьет!" Здесь ситуация обратная детским кубикам, где для построения чего-либо достаточно чертежа - соединение кубиков друг с другом очевидно. MD-программа - это, скорее, красивый розовый домик, в разных комнатах которого надо расставлять мебель, селить Барби и Кена (и не дай бог перепутать).
2. Определения необходимых Win-API сущностей. В примере - жалкие огрызки бесконечных Win-справочников, а в обезъянниках - гиперссылки на эти самые справочники. По идее, это каталог кубиков (прайс-лист какой-нибудь "икеи" в Барби-модели).
3. Win-парадигмы. Вот тут мои примеры немного симпатичнее страшно выглядящих asm- и C-вызовов, т.к. мне удалось хоть как-то засунуть общие куски в универсальные слова. Т.е. хотя бы на этом уровне удалось загнать внутрь "кубиков" хоть немного MD-требухи.
4. Смысловая часть примеров. Ни у меня, ни в обезьянниках ее практически невозможно отличить от (3). А ведь здесь было бы самое место чертежу.
А применимо ли вообще понятие "кубика" к программированию? Исторически это очень близко к машинам-бусинам Дейкстры и конструкциям структурного программирования. Объектно-ориентированное программирование - это, скорее, уже отход от данной схемы, т.к. кубики стали в большинстве случаев нестыкуемыми. Т.о. налицо следующие проблемы.
1. Необходим какой-либо справочник, пусть убогий для того, чтобы обрисовать хотя бы примерную область применения показанного в примере API-средства.
2. Необходимо как-то разграничить примененные в примере виды данных и программные структуры на те, которыми можно "поиграть" для модификации примера (цвет фона, позиция Control, текст приглашения...), те, которые важны для примера (стиль окна, обрабатываемые сообщения...), и те, которые должны выступать в жесткой связке (открывающие и закрывающие функции, имена классов, handlers...).
Вводить для каждого примера базу данных, содержащую в виде доменов полные множества внешних параметров? Мол, в примере, я использовал именно этот кортеж входных данных, но заполнив его другими допустимыми значениями, я получу пример с немного другой функциональностью. Правда, это будет уже не база данных, а, скорее, база знаний, т.к. в ней придется хранить и мощный фильтр недопустимых кортежей, составленных вроде бы из вполне законных значений.
Последний раз редактировалось: Gudleifr (Вс Апр 05, 2020 4:04 pm), всего редактировалось 1 раз(а)
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Re: WIN-FORTH для минималистов (проект FOBOS)
ИНСТРУКЦИЯ ПО УСТАНОВКЕ ПРОЕКТА НА ВАШЕМ КОМПЬЮТЕРЕ
(Такие сложности были нужны т.к. на моем старом хостинге не было возможности хранить исполняемые файлы и архивы. Сейчас, конечно, можно сразу использовать .exe и .dll).
Алгоритм У. УСТАНОВКА (Создание работоспособной win-версии FOBOS).
Входные параметры: Набор HTML-ссылок на текстовые файлов.
У1. [Директорий.] Создать в удобном для Вас месте новый директорий (папку, каталог) и загрузить туда текстовые файлы средствами вашего Internet-браузера (следите за именами файлов).
У2. [Командный.] Найти в директории файл install.txt и переименовать его в install.bat . Запустить его на исполнение. []
Немного подробнее:
Команды в install.bat делятся на три группы:
debug <файл -- создание bin-файла, по содержимому соответствующему нужному exe или dll.
ren имя.bin имя.exe (.dll) -- переименование файла
copy имя1.exe (.dll) имя2.exe (.dll) -- копирование файлов для создания FORTH-программ с тем же ядром, но приспособленных под другой текстовый довесок.
После исполнения командного файла в директории появятся несколько exe-файлов (все одинаковые, и, в принципе, достаточно одного) и dll-файлов (тоже все одинаковые). Если exe-файлы можно запускать как и не указывая имя txt-файла (т.е будет использован txt-файл того же директория с тем же именем), так и с явным указанием txt-файла (будет использован файл с указанным именем (путем) и расширением .txt), при использовании библиотек возможен только первый вариант.
***
Как с этим работать: найти в файле g2.txt нужный пример и раскомментировать в нем последнюю строчку. Запустить g2.exe.
ФАЙЛЫ - RAR, 0.32Мб
коды exe-файла - g2bin.txt
коды dll-файла - g4bin.txt
все примеры - g2.txt
простое WIN-приложение для примера 14 - g3.txt
простая библиотека для примера 17 - g4.txt
hook-библиотека для примера 24 - g5.txt
splash-библиотека для примера 26 - g6.txt
подвисающее приложение для примера 29 - g7.txt
иконки для примера 19 - list.bmp
картинка для примера 25 - tweety78.bmp
заставка для примера 26 - JourneyStart.bmp
командный файл инсталляции - install.txt
ПРИЛОЖЕНИЕ
исходный текст exe-файла на языке ассемблера - g2asm.txt
исходный текст dll-файла на языке ассемблера - g4asm.txt
готовый g2.exe (и остальные g?.exe)
готовый g4.dll (и остальные g?.dll)
ICZELION'S WIN32 ASM TUTORIAL (англ.). Part I - masm32-1.txt
ICZELION'S WIN32 ASM TUTORIAL (англ.). Part II - masm32-2.txt
ICZELION'S WIN32 ASM TUTORIAL (англ.). Part III - masm32-3.txt
Лицензия GNU - http://www.gnu.org/licenses/gpl.html
(Такие сложности были нужны т.к. на моем старом хостинге не было возможности хранить исполняемые файлы и архивы. Сейчас, конечно, можно сразу использовать .exe и .dll).
Алгоритм У. УСТАНОВКА (Создание работоспособной win-версии FOBOS).
Входные параметры: Набор HTML-ссылок на текстовые файлов.
У1. [Директорий.] Создать в удобном для Вас месте новый директорий (папку, каталог) и загрузить туда текстовые файлы средствами вашего Internet-браузера (следите за именами файлов).
У2. [Командный.] Найти в директории файл install.txt и переименовать его в install.bat . Запустить его на исполнение. []
Немного подробнее:
Команды в install.bat делятся на три группы:
debug <файл -- создание bin-файла, по содержимому соответствующему нужному exe или dll.
ren имя.bin имя.exe (.dll) -- переименование файла
copy имя1.exe (.dll) имя2.exe (.dll) -- копирование файлов для создания FORTH-программ с тем же ядром, но приспособленных под другой текстовый довесок.
После исполнения командного файла в директории появятся несколько exe-файлов (все одинаковые, и, в принципе, достаточно одного) и dll-файлов (тоже все одинаковые). Если exe-файлы можно запускать как и не указывая имя txt-файла (т.е будет использован txt-файл того же директория с тем же именем), так и с явным указанием txt-файла (будет использован файл с указанным именем (путем) и расширением .txt), при использовании библиотек возможен только первый вариант.
***
Как с этим работать: найти в файле g2.txt нужный пример и раскомментировать в нем последнюю строчку. Запустить g2.exe.
ФАЙЛЫ - RAR, 0.32Мб
коды exe-файла - g2bin.txt
коды dll-файла - g4bin.txt
все примеры - g2.txt
простое WIN-приложение для примера 14 - g3.txt
простая библиотека для примера 17 - g4.txt
hook-библиотека для примера 24 - g5.txt
splash-библиотека для примера 26 - g6.txt
подвисающее приложение для примера 29 - g7.txt
иконки для примера 19 - list.bmp
картинка для примера 25 - tweety78.bmp
заставка для примера 26 - JourneyStart.bmp
командный файл инсталляции - install.txt
ПРИЛОЖЕНИЕ
исходный текст exe-файла на языке ассемблера - g2asm.txt
исходный текст dll-файла на языке ассемблера - g4asm.txt
готовый g2.exe (и остальные g?.exe)
готовый g4.dll (и остальные g?.dll)
ICZELION'S WIN32 ASM TUTORIAL (англ.). Part I - masm32-1.txt
ICZELION'S WIN32 ASM TUTORIAL (англ.). Part II - masm32-2.txt
ICZELION'S WIN32 ASM TUTORIAL (англ.). Part III - masm32-3.txt
Лицензия GNU - http://www.gnu.org/licenses/gpl.html
Gudleifr- Admin
- Сообщения : 3399
Дата регистрации : 2017-03-29
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения