Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > VB6 > Название одной функции как параметр другой


Автор: I_Am_Rock 11.8.2010, 23:59
Всем добрый день.  smile 

Вот такая проблема возникла. Помогите, пожалуйста.

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

К примеру,
Код


MyFunc2 (MyFunc1)

Function MyFunc1()
'код
End Function


Насколько я понимаю (объясните, если я ошибаюсь) такой же принцип в случае сабклассинга.
Ведь там если SetWindowLong используется с GWL_WNDPROC, то в качестве третьего параметра адрес новой функции для окна.

Но там всё понятно - аддрессоф возвращает адрес функции. 

А вот как мне быть? Как это реализовывается изнутри?

 smile 

Автор: Akina 12.8.2010, 00:10
Если функция является методом объекта - то CallByName().
А если нет... ну сделай обёртку типа

Код

Sub FNCall(FNName As String)
Select Case UCASE(FNName)
  Case "FUNC1"
    Call Func1
  Case "FUNC2"
    Call Func2
  Case "FUNC3"
    Call Func3
'...
  Case Else
    Err.Raise 35
End Select
End Sub

Автор: I_Am_Rock 12.8.2010, 11:31
Цитата(Akina @  12.8.2010,  00:10 Найти цитируемый пост)
Если функция является методом объекта - то CallByName().

Нет

Цитата(Akina @  12.8.2010,  00:10 Найти цитируемый пост)
А если нет... ну сделай обёртку типа

Не получится - заранее низвестно название функции, переданной как параметр.

Тут вот какое дело.
Допустим, я пишу модуль с функцией FuncIAmRock, которая что-то делает, а затем (в определенный момент) вызывает функцию, как-то переданную ей в виде параметра. Вот эта самая функция - которая передается как параметр - она пишется не мною, а человеком, который и вызывает мою.

Вот как я пытаюсь решить.
Допустим, моя функция сидит в модуле ModuleIAmRock. Другой человек подключает мой модуль к своему проекту.
и вызывает функцию
Код

Private Sub Form_Load()
g = FuncIAmRock(AddressOf SomeFunc)
End Sub


Затем этот же человек пишет свою функцию SomeFunc. Для этого ему надо создать уже свой модуль (ну, это требование addressof, насколько я знаю)

Код

Function SomeFunc()
MsgBox "Hello"
End Function


А вот как я пытаюсь сделать свою функцию. И она работает! - только потом вылетает с ошибкой.
Код

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Function FuncIAmRock(ByVal z As Long)
CallWindowProc z, 0, 0, 0, 0
End Function


Я понимаю, что CallWindowProc предназначена не для этого, но может ее можно как-то приспособить...


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

Я прикрепляю этот тестовый проект.

Добавлено @ 11:37
Проблема решена - здесь тупо не нужно было писать addressof  smile

Добавлено @ 11:43
аааааа  smile 
Теперь новая проблема, но из той же оперы

Вот код формы
Код

Private Sub Form_Load()
g = FuncIAmRock(SomeFunc)
End Sub

Function SomeFunc()
a = 4 + 5
MsgBox a
End Function


А вот код моего модуля
Код

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Function FuncIAmRock(ByRef z As Long)
MsgBox "1"
CallWindowProc z, 0, 0, 0, 0
MsgBox "2"
End Function


Все работает, но (!!!) сначала показывается 9, а затем 1 и 2. Хотя ведь должен быть такой порядок 1, 9, 2

 smile

Добавлено @ 11:44
А, ну ведь тут происходит вызов функции из функции, а не передача функции как параметра...

Кому не лень было всё это прочитать - подскажите!

Автор: Akina 12.8.2010, 11:50
а так?

Код

Function FuncIAmRock(ByRef z As Long)
MsgBox "1"
DoEvents
CallWindowProc z, 0, 0, 0, 0
MsgBox "2"
End Function

Автор: I_Am_Rock 12.8.2010, 13:26
Пробовал - аналогично.

Причину я понял - если вызываешь вот так g = FuncIAmRock(SomeFunc), то просто сначала выполняется SomeFunc, а затем сама FuncIAmRock. А CallWindowProc вообще в данном случае не выполняется, потому что в z ничего нет (в данном случае).

Так что это мне только показалось, что это работает.

А на самом деле правильный путь - это моя первая попытка - где аддрессоф - т.е. тот, который в прикрепленном файле в предыдущем посте.

Вот только почему после выполнения CallWindowProc возникает ошибка!! smile 

Автор: I_Am_Rock 12.8.2010, 16:07
ололо вспомнил, что были уже у меня случаи, когда в среде не запускается, а екзешник работает нормально. Попробовал - и в этом случае так.

Но это не нормальное решение проблемы. Поэтому тему лучше не закрывать, я думаю. У кого будут какие мысли - пишите.

Для тех, кто зайдет в эту тему и не поймет, то правильное решение - это то, что в прикрепленном файле во 2 посте.

Спасибо Akina за то, что пытался помочь  smile 

Автор: Akina 12.8.2010, 16:24
Ну в принципе у Офиса есть функция Eval, которая выполняет оператор из строковой переменной в текущем контексте. Можно попробовать прицепить референсную либу к проекту и использовать - вдруг заработает?

Но вообще при вашей (извини, но черезжопной) методике работы я бы предложил вам оформлять ваши модули в виде модуля класса, а соответственно все процедуры и функции станут методами этого класса. Тогда тебе присылается новая версия модуля, ты заменяешь старый модуль, на старте создаёшь экземпляр класса и спокойно вызываешь нужные тебе процедуры и функции через CallByName. Более того, у тебя появится возможность энумеровать их, проверять существование, получать подсказку и автозаполнение в GUI и прочие вкусности.

Автор: I_Am_Rock 12.8.2010, 16:45
Я объясню почему так. Только не смейся, если я ошибаюсь. ;)

Вообще, задача - написать dll на асме, которая автоматизирует работу с добрым десятком api-функций, а к ней собой доступ через экспортную функцию (это та самая, которую я для примера назвал FuncIAmRock).

Но ассемблер - не такая вещь, где легко пробовать - добавлять и убирать куски кода (по крайней мере, для меня). Поэтому сначала я пишу на VB.

И если я сейчас сделаю через модуль класса, то на асме у меня никаких классов не будет.

Автор: Dexx 12.8.2010, 23:01
Может так.

пишем dll на асме с этой самой экспортной функцией(с максимально нужным количеством параметров которые нужно будет передавать в вызываемые функции+название вызываемой функции) . 
далее анализируем какую нужно функцию и передаем управление на нужный кусок кода.
но тут все пишется в dll на асме

а в вб
 просто объявляем что то типа 
Код

Public Declare Function FuncIAmRock  Lib "FuncIAmRock"  (ByVal FuncName As any, ByVal, param1 as any, ByVal, param2 as any .....) As Long


пользуем как то так
Код

 FuncIAmRock("kill", procN,0,0,..)


Если трудно пробовать dll на асме, пробуй dll на делфи.

Ну если я что то не так понял извините.

Автор: I_Am_Rock 13.8.2010, 08:58
Dexx, да я и собираюсь так сделать. С этим проблем нет  smile 

Автор: Dexx 15.8.2010, 01:20
тогда все вопросы в asm ветку  форума.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)