tag:blogger.com,1999:blog-1702873441071265539.post27014892634102476..comments2023-05-29T19:02:20.570+03:00Comments on Блог GunSmoker-а: Исправляем плохой дизайн API: функции обратного вызова без user-аргументаGunSmokerhttp://www.blogger.com/profile/15611696588191431330noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-1702873441071265539.post-45020212574181858942017-04-20T12:11:20.171+03:002017-04-20T12:11:20.171+03:00Я без понятия, не эксперт в GUI. Возможно - истори...Я без понятия, не эксперт в GUI. Возможно - исторически, возможно - хотели оставить поле свободным для прикладных программистов.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-28468677067177873042017-04-20T11:57:46.030+03:002017-04-20T11:57:46.030+03:00Большое спасибо!
Непонятно тока почему когда практ...Большое спасибо!<br />Непонятно тока почему когда практически все всюду делают через GWL_USERDATA или на крайний случай SetProp - почему VCL решили так вот раскорячиться-то?))<br />Ещё и вот: https://habrahabr.ru/post/217189/Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-88512565462773322042017-04-14T01:58:11.300+03:002017-04-14T01:58:11.300+03:00Я не особо эксперт в GUI, но я бы делал через GWL_...Я не особо эксперт в GUI, но я бы делал через GWL_USERDATA:<br />- При создании: SetWindowLongPtr(Wnd, GWL_USERDATA, LPARAM(Self));<br />- В оконной процедуре: YourObject := TYourClass(Pointer(GetWindowLongPtr(Wnd, GWL_USERDATA))); if Assigned(YourObject) then Result := YourObject.DialogProc(Msg, wParam, lParam);<br />- При уничтожении: SetWindowLongPtr(Wnd, GWL_USERDATA, 0);<br /><br />MakeObjectInstance работает примерно так же, как описано в этой статье (AllocTemplate) - только MakeObjectInstance не универсальна, а жёстко привязана к конкретному прототипу. Иными словами, она тоже динамически создаёт машинный код (выделяет память с EXECUTE), пишет туда вызов метода объекта, передавая параметры. Сам объект извлекается из константы, записанной в этом же динамически сгенерированном коде.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-56323928114006189152017-03-30T04:49:29.776+03:002017-03-30T04:49:29.776+03:00Я рассматриваю варианты как сделать связку класс +...Я рассматриваю варианты как сделать связку класс + окно. То есть надо создать класс (ООП), при создании делать CreateWindowEx(), и при этом как-то связать оконную функцию и экземпляр класса. Чтоб внутри WndProc было ясно которому объекту класса пришло сообщение.<br />Пока нашёл варианты:<br /> * GWL_USERDATA/GWL_ID через lpParam<br /> * SetProp() через lpParam<br /> * какая-то странная подмена WndProc и глобальная переменная что я наблюдаю в Делфи7.VCL.Controls<br />Что бы вы посоветовали делать, а что не делать? Спасибо!Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-9987085609715484782017-03-30T04:23:12.044+03:002017-03-30T04:23:12.044+03:00Случайно нашёл статью Гуглом по "MakeObjectIn...Случайно нашёл статью Гуглом по "MakeObjectInstance", странно что я раньше её не видел. Спасибо огромное, очень познавательно!<br />А не могли бы пояснить чуть подробнее каким образом работает MakeObjectInstance? Ковырял исходный код Делфи7, нашёл MakeObjectInstance, и как-то до сих пор не до конца понимаю что она делает...Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-16047365363177709042013-12-09T12:12:32.989+04:002013-12-09T12:12:32.989+04:00Достаточно всего лишь явно задавать значение для ф...Достаточно всего лишь явно задавать значение для функции. Например, так:<br /><br />function InternalCallback(FoundData: TData): BOOL; cdecl;<br />var<br /> RealCallback: Pointer;<br />begin<br /> RealCallback := Pointer($90ABCDEF);<br /> Result := TRealCallbackFunc(RealCallback)(FoundData, Pointer($12345678));<br />end;<br /><br />Соответственно, в шаблоне в явном виде будут числа $12345678 (для параметра) и $90ABCDEF (для адреса функции) - вот их и заменяйте. Аналогичное справедливо и для ARM.<br /><br />P.S. Для 64-битного шаблона имеет смысл использовать удвоенные волшебные значения: какой-нибудь $1122334455667788 и $9900AABBCCDDFF - проще будет определять их границы в машинном коде. Не забывайте только про little endian.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-47913430521476242282013-12-09T09:05:29.985+04:002013-12-09T09:05:29.985+04:00Не могу сообразить, как сделать шаблон под Win64. ...Не могу сообразить, как сделать шаблон под Win64. Что-то не так с адресами.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-72245513295885299712013-10-06T14:00:48.816+04:002013-10-06T14:00:48.816+04:00>>> костыль, не работающий в х64, требущи...>>> <i>костыль, не работающий в х64, требущий нетривиальных знаний асма</i><br /><br />1. С чего бы это ему не работать в x64? Указанный подход будет работать для любой платформы, но, конечно, константа шаблона должна быть своей для каждой платформы.<br />2. В данной статье не требовалось вообще никаких знаний ассемблера. Абсолютно. Ровно потому, что мы не касались ассемблера, а работали только с машинным кодом. Увидеть два указателя в коде и заменить их на свои - это действительно нетривиальные знания?<br /><br />>>> <i>Единственный недостаток глобальной переменной</i><br /><br />Вовсе нет. Подумай о такой функции как SetWindowsHookEx. К примеру, наш класс реализует окно-диалог и хочет установить фильтр-хук на сообщения, для мониторинга сообщений в контролы диалога. Никакой threadvar здесь не поможет, потому что в одном потоке есть тьма окон.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-88462815224878258652013-09-04T10:47:39.265+04:002013-09-04T10:47:39.265+04:00Очень интересно! Но не может не всплывать вопрос.
...Очень интересно! Но не может не всплывать вопрос.<br />Между "глобальными переменными" и "классовыми методами" (так и хочется их назвать - статическими" существует ещё один промежуточный вариант.<br /><br />Глобальная переменная-ссылка на экземпляр.<br />Данные выскребаются по ссылки для конкретного вызова в коде callback-а, а вот в ссылку можно задвинуть любой объект из пула.Всеволод Леоновhttp://blogs.embarcadero.com/vsevolodleonovnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-14405919064589482262013-08-30T01:25:48.951+04:002013-08-30T01:25:48.951+04:00«jack128 комментирует...
Я так и не понял, почему ...«jack128 комментирует...<br />Я так и не понял, почему простой, понятный любому школьнику код с глобальной переменной - это плохо, а костыль, не работающий в х64, требущий нетривиальных знаний асма - это хорошо.»<br />-- Ну, не совсем...<br />Представьте себе, если Вам придётся вызывать некоторую функцию F, которая передаст управление в функцию G в качестве call-back, с передачей аргумента P через глобальную переменную.<br />Что будет, если в процессе выполнения G управление снова будет передано в F, а она, в свою очередь снова инициирует выполнение G?<br />- Ничего хорошего, поскольку первый и второй вызов G будут использовать одну и ту же область памяти для работы с параметром P, востребованных в разных ситуациях (первый и второй вызовы F).<br />Плохи оба решения. Но соглашусь, что второе - хуже :-)<br />IMHO шаманства следует избегать, код приобретать только в исходниках, чтобы иметь возможность внести необходимые изменения.<br /><br />К варианту с "динамическим кодом" IMHO следует прибегать только в самых крайних случаях, до которых лучше не доводить.<br />Подробно - здесь: http://ru.wikipedia.org/wiki/Реентерабельность.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-50628694524027660212013-08-28T14:21:58.331+04:002013-08-28T14:21:58.331+04:00Я так и не понял, почему простой, понятный любому ...Я так и не понял, почему простой, понятный любому школьнику код с глобальной переменной - это плохо, а костыль, не работающий в х64, требущий нетривиальных знаний асма - это хорошо. Единственный недостаток глобальной переменной - это неработоспособность в многопоточном ПО, но для этого есть threadvarjack128https://www.blogger.com/profile/06241586079811572654noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-35422026071406478182013-08-28T10:15:26.550+04:002013-08-28T10:15:26.550+04:00Это про MakeObjectInstance? Она предназначена для ...Это про MakeObjectInstance? Она предназначена для более узкой задачи: конвертировать оконную процедуру. <br /><br />Откуда следует:<br />1. Она не потокобезопасна (поскольку с окнами VCL работает только в главном потоке, то нет необходимости делать служебные функции потокобезопасными).<br />2. Она крайне сильно привязана к прототипу оконной функции (в её исходном коде есть явная ссылка на прототип stdcall функции с 4-мя параметрами, которые упаковываются в TMessage - см. StdWndProc). Соответственно, целевой метод может быть исключительно вида procedure TApplication.WndProc(var Message: TMessage);<br />3. Каждый вызов MakeObjectInstance выделяет блок памяти, который не освобождается. Все блоки памяти освобождаются в конце работы программы.<br /><br />Откуда видно, что MakeObjectInstance не приемлема для указанной задачи в общем случае. <br /><br />А так идея у MakeObjectInstance та же самая (дин. генерация кода), только что вместо простого push user-параметр там используется несколько "черезжопное" на мой взгляд решение.<br /><br />К тому же смысл поста - показать, как что-то можно сделать своими руками.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-23006254805032563062013-08-28T08:44:40.296+04:002013-08-28T08:44:40.296+04:00А подход на ассемблере, включая x64? Чем тут не ус...А подход на ассемблере, включая x64? Чем тут не устроил<br />http://www.sql.ru/forum/1032828/hochu-izbavitsya-ot-globalnoy-peremennoy<br /><br />?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-23495680945783145312013-08-28T06:45:14.905+04:002013-08-28T06:45:14.905+04:00"Я добавил в текст примечание в конце."
..."Я добавил в текст примечание в конце."<br /><br />Да - там всё логично.Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-41744949704236011062013-08-28T05:42:08.947+04:002013-08-28T05:42:08.947+04:00>>> А вы же сами тут ассемблер приводите ...<i> >>> А вы же сами тут ассемблер приводите :-) Нет тут небольшого нарушения логики? </i><br /><br />Я добавил в текст примечание в конце.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-73610940702215143912013-08-28T05:21:01.974+04:002013-08-28T05:21:01.974+04:00"Лучше не связываться с этим, не изучив архит..."Лучше не связываться с этим, не изучив архитектуру. Там много разных мелочей. "<br />Ну да. Не хочется если честно сильно в это влезать. Пыл уже не тот.<br /><br />"В общем, моя мысль следующая: если уж вы возьмётесь за переделывание - то почему бы не переделать сразу как следует: без ассемблера и с передачей параметров, либо классом/объектом (читай: записью)?"<br /><br />Ну в целом - я конечно к этому склоняюсь.Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-9406732702793740982013-08-28T05:17:47.375+04:002013-08-28T05:17:47.375+04:00Смотрите, если вы хотите поддержку 64 бит - вам ну...Смотрите, если вы хотите поддержку 64 бит - вам нужно переделывать код. Местами - весьма существенно. И раз так - стоит ли переделывать его на ещё один вариант ассемблерного кода? А если завтра будете пытаться запустить код на ARM (Android/iOS)? <br /><br />В общем, моя мысль следующая: если уж вы возьмётесь за переделывание - то почему бы не переделать сразу как следует: без ассемблера и с передачей параметров, либо классом/объектом (читай: записью)?GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-29128083965753580852013-08-28T05:14:20.124+04:002013-08-28T05:14:20.124+04:00>>> Я просто с 64-хбитной архитектурой - ...<i> >>> Я просто с 64-хбитной архитектурой - слабо знаком.</i><br /><br />Лучше не связываться с этим, не изучив архитектуру. Там много разных мелочей. Другая адресация, другая модель вызова, выравнивание стека (весьма неочевидное требование, кстати, из-за которого код может влёгкую "как бы работать", но "случайно" вылетать - причём вылетать не с AV, а прям фатально, поскольку ОС просто завершит процесс в котором явно что-то напутано) и т.п. GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-47522226917687795882013-08-28T05:14:04.492+04:002013-08-28T05:14:04.492+04:00"Да, примерно так. x86-64 передаёт RBP явно, ..."Да, примерно так. x86-64 передаёт RBP явно, как параметр."<br /><br />Ну примерно понятно. Ладно. Буду думать. Спасибо!Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-72387134827132978642013-08-28T05:11:17.961+04:002013-08-28T05:11:17.961+04:00Да, примерно так. x86-64 передаёт RBP явно, как па...Да, примерно так. x86-64 передаёт RBP явно, как параметр.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-26623401298983196602013-08-28T05:08:26.268+04:002013-08-28T05:08:26.268+04:00"Я не уверен, что понял в чём состоит проблем..."Я не уверен, что понял в чём состоит проблема."<br /><br />Жаль. Ну ладно. Спасибо!Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-58596296256117858852013-08-28T05:07:22.599+04:002013-08-28T05:07:22.599+04:00"Из-за особенностей модели вызова в x86-64 лю..."Из-за особенностей модели вызова в x86-64 любая внутренняя функция имеет скрытый параметр - указатель на локальные переменные её контейнера (т.е. некий аналог Self)"<br /><br />В 32-х битах ведь этим аналогом регистр ebp является? Так? Собственно мои "обёртки" его и корректируют?<br /><br />Я просто с 64-хбитной архитектурой - слабо знаком.Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-1292429854732595152013-08-28T05:04:18.535+04:002013-08-28T05:04:18.535+04:00Я не уверен, что понял в чём состоит проблема.Я не уверен, что понял в чём состоит проблема.GunSmokerhttps://www.blogger.com/profile/15611696588191431330noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-43300031138171564202013-08-28T05:04:11.637+04:002013-08-28T05:04:11.637+04:00"Лучше всего забыть про ассемблер и указатели..."Лучше всего забыть про ассемблер и указатели на локальные функции."<br /><br />А вы же сами тут ассемблер приводите :-) Нет тут небольшого нарушения логики?Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-1702873441071265539.post-24350592026968586572013-08-28T05:02:40.498+04:002013-08-28T05:02:40.498+04:00"Лучше всего забыть про ассемблер и указатели..."Лучше всего забыть про ассемблер и указатели на локальные функции."<br /><br />Да это-то понятно. Но уж очень много переделывать.<br /><br />"Из-за особенностей модели вызова в x86-64 любая внутренняя функция имеет скрытый параметр - указатель на локальные переменные её контейнера (т.е. некий аналог Self). "<br /><br />А это знание ничем помочь не может?Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.com