Динамическое создание функций в run-time. Как реализовать?

Разговоры на любые темы: вы можете обсудить здесь какой-либо сайт, найти единомышленников или просто пообщаться...
jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Динамическое создание функций в run-time. Как реализовать?

Сообщение jangle » 25.03.2008 (Вт) 11:59

Никак не могу придумать, как реализовать. Допустим есть такая функция.

Код: Выделить всё
Function Foo1(ByVal X as Long) as Long
....
....
End Function


В процессе работы программы, мне нужно создать несколько экземпляров таких функций. Эти функции, я вызываю по указателю.
Программка на PB, поэтому всякий ООП здесь не прокатит

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 25.03.2008 (Вт) 12:26

Первое, что приходит в голову (это только предположение) - склонировать участок памяти, занимаемый функцией, с помощью CopyMemory. Потом VirtualProtect и остальные па.

А зачем это вообще нужно?
Лучший способ понять что-то самому — объяснить это другому.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 12:30

Нужно для подключения плагинов, у каждого плагина должна быть своя CallBack функция внутри основной программы, для обмена данными. Количество подключенных плагинов, заранее неизвестно и может быть произвольным

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 12:35

jangle
Создаёшь новую приватную кучу, изначально выставляя её выполняемой. (Можешь конечно возиться с Virtual(Alloc|Protect|Free), если есть желание делать свой механизм куч).

Для каждой новой динфункции вызываешь HeapAlloc (нужного размера) и затем делаешь CopyMemory туда код своей оригинальной функции функции.

Удаляешь соответственно HeapFree-ом.

В конце приватную кучу также уничтожаешь HeapDestroy-ем.

Antonariy
Применений может быть великиое множество: динамические WindowProc-и, узлы конечных автоматов и т.д.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 13:50

Cпасибо, действительно, оказывается проще всего скопировать функцию в другое место. Можно даже запихнуть ее в переменную и вызывать от туда. Нашел вот такой код, как раз то что нужно:

Код: Выделить всё
#Compiler PBWin
#Compile Exe
#Dim All

Declare Function template (ByVal param As Long) As Long
'
Function work(ByVal param As Long) As Long
    Local s As Long
    s=param*100&
    Function=s
End Function
'
Function PBMain () As Long
  Local fn,dwRes,fake As Dword
  Dim sFunc As Static String *1024
' copy function to string
  sFunc=Peek$(CodePtr(work),CodePtr(PBMain)-CodePtr(work))
  Open "FunctionInString.bin" For Output As #1
    Print #1, sFunc; 'Save important function as external file.You can even crypt it.
  Close #1
'=====================================
  sFunc="" '<------- just for prove
  Open "FunctionInString.bin" For Binary As #1
    Get$ #1,Lof(1),sFunc ' If will be crypted , then run uncrypt algo
  Close #1
' get address of string
  fn=VarPtr(sFunc)
' Call function located in string
  Call Dword fn Using template(ByVal 20&) To dwRes
' Display result of function in string
  ? Str$(dwRes)
 
  Call Dword fn Using template(ByVal 40&) To dwRes
' Display result of function in string
  ? Str$(dwRes)
 
 
End Function           

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 13:52

Этот код НЕЛЬЗЯ использовать. Ни в коем случае.

Он DEP-Unsafe.

По логике этого кода - динкод помещается в стек -- это грубейшее нарушение.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 14:04

Хакер писал(а):Этот код НЕЛЬЗЯ использовать. Ни в коем случае.

Он DEP-Unsafe.

По логике этого кода - динкод помещается в стек -- это грубейшее нарушение.


Странно, включил режим DEP для всех программ, перезагрузил комп. Попробовал запустить этот пример. Работает однако... Может он его в стек не помещает?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 14:09

Вряд ли локальные переменные помещаются не в стек. Впрочем, я не знаю, как это сделано в PB.

Возможно, это баги DEP. На некоторых процессорах он хоть и включен, работает неадекватно.

Возможно, что PB перед тем как делать Call Dword fn Using template(ByVal 20&) To dwRes ставит странице с fn E-флаг. Это тоже плохо - данные не должны быть execut-абельными, иначе от вторжений никакой DEP не спасёт.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 14:17

Кстати, я где-то видел пример использования ассемблера в VB6. Там ассемблерная строка, компилировалась в HEX последовательность, и потом запускалась из VB-переменной, API функцией CallWindowProc.
IMHO здесь тоже самое. Или я ошибаюсь?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 14:21

Это морально устаревшие кривые примеры. Видел ты их в FAQ.

Когда их писали - небыло DEP.

Теперь (да, собственно, всегда: но теперь - особо строго) код должен быть исключительно в R_E-страницах, а данные - в R(W)_-страницах.


Что тебе мешает использовать приватную кучу?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 14:34

Надо будет попробовать пример с приватой кучей, мне важно чтобы программа работала на всех машинах. И всякие потенциальные проблемы иметь неохота

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Сообщение ANDLL » 25.03.2008 (Вт) 16:00

[Хакер] :: Нецензурщина вырезена.

Нужно для подключения плагинов, у каждого плагина должна быть своя CallBack функция внутри основной программы, для обмена данными. Количество подключенных плагинов, заранее неизвестно и может быть произвольным
Конкретно в описанной задаче генерировать новую функию вообще не нужно.
Я понимаю желание людей узнавших ассемблер применить его в первой попавшейся задаче, но все же надо знать меру:)
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 16:37

Конкретно в описанной задаче генерировать новую функию вообще не нужно.


Почему не нужно? Представть, что все плагины пишут данные одновременно в программу-сервер, причем с разной скоростью. Гораздо удобнее, если для каждого есть своя CallBack функция, чтобы сервер смог отреагировать на активность плагина, в промежутке занимаясь другими делами

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 16:42

jangle
У тебя сгенерированные callback-и будут чем то отличаться друг от друга?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Сообщение ANDLL » 25.03.2008 (Вт) 16:50

Нет, гораздо удобнее это когда одна callback функция и у нее есть параметр отвечающий за то, какой именно плагин ее вызвал. По крайней мере это правильнее :)
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 17:10

У тебя сгенерированные callback-и будут чем то отличаться друг от друга?


Ничем, одни все однотипные.

Нет, гораздо удобнее это когда одна callback функция и у нее есть параметр отвечающий за то, какой именно плагин ее вызвал. По крайней мере это правильнее


Вот как раз определить, какой из плагинов отправил данные я не могу. Плагин просто вызывает мою функцию, и передает в нее параметры без всякой индификации. Поэтому, и появилась мысль, сделать для каждого свою callback

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 17:11

Ничем, одни все однотипные.

Тогда смысла действительно нет.


Вот как раз определить, какой из плагинов отправил данные я не могу. Плагин просто вызывает мою функцию, и передает в нее параметры без всякой индификации. Поэтому, и появилась мысль, сделать для каждого свою callback

Ну так программа же твоя - измени протокол общения плагинов с программой - введи дополнительный параметр - хэндл плагина.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 25.03.2008 (Вт) 17:38

Ну так программа же твоя - измени протокол общения плагинов с программой - введи дополнительный параметр - хэндл плагина.


Это невозможно. Протокол фиксирован разработчиками плагинов изменить его нельзя. Хендл тоже немогу узнать, т.к. моя программа сама выдает хендл, своей CallBack функции, когда ей приходит команда типа: "Выдай мне указатель на свою функцию, куда буду передавать тебе данные. А затем вызови скриптовый движок, функцию XXXX в скрипте, и передай в нее мои данные"...

Т.е. моя программа это промежуточный, интерфейсный слой, между плагинами и скриптовой частью cистемы. Задача состоит в трансляции данных из плагинов, в определенные функции скрипта, в тот момент, когда происходит передача очередной порции данных.

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Сообщение ANDLL » 25.03.2008 (Вт) 17:44

Эмм, ну это тяжкий случай архитектурной дистрофии....
Ну значит HeapAlloc и фперед...
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.03.2008 (Вт) 17:45

Тогда сделай в своей проге-посреднике диспетчер.
Заглушки будут вызывать основную callback-процедуру, передавая в нее также идентификатор родителя.
Lasciate ogni speranza, voi ch'entrate.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 18:00

Могу предложить ещё один блэккодинговый вариант: определять вызывающий плагин по адресу возврата в стеке.

Предупреждаю сразу, что способ ненадёжен. Например - если кэлбэк вызывается через тот же CallWindowProc.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 25.03.2008 (Вт) 20:28

Есть вариант с созданием динамического переходника. В кучу с правами на выполнение записывается последовательность команд:
pop eax
push plug_id
push eax
push func_adr
ret

Вместо plug_id подставить унакальный для каждого плагина номер, вместо func_adr - адрес функции обработчика.
Переходник добавит в стек id-плагина и он окажется первым параметром функции. Переходник работает при stdcall конвенции вызова. Для других конвенций нужен другой переходник. Данный подход хорош тем, что не надо создавать копию функции, а нужно всего лишь несколько байт на плагин.
Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 25.03.2008 (Вт) 20:29

[offtopic]
keks-n
И получаем что? Правильно :) -- прототип таблицы интерцепторов.
[/offtopic]
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 25.03.2008 (Вт) 20:31

Я так CompletionRoutine классо-зависимой делал. Работало.
Изображение


Вернуться в Народный треп

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 16

    TopList