Вызов любых функций по указателю - VB

Узнай цену своей работы

Формулировка задачи:

Пока не работал форум, ковырялся в рантайме VB . Иследуя функции VBA6 придумал способ вызова функций по указателю. Все просто. Объявляем прототип функции (пустую функцию), где дополнительно первым параметром будет передаваться адрес функции. Далее пропатчиваем его, таким образом чтобы он перекидывал нас по адресу заданному первым параметром. Таким образом можно вызывать функции в стандартных модулях, модулях класса, формы, API-функции (например полученные через LoadLibrary и GetProcAddress). Одно замечание, пока не выяснил причину, желательно запускать проект через Ctrl+F5, т.к. иногда может не работать указатель или же вообще происходить вылет. А так работает и в IDE и в скомпилированном виде. Пример вызова по указателю обычных функций модуля.
Листинг программы
  1. Private Declare Function GetMem4 Lib "msvbvm60" (src As Any, dst As Any) As Long
  2. Private Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
  3. Private Declare Sub EbGetExecutingProj Lib "vba6" (hProject As Long)
  4. Private Declare Function TipGetFunctionId Lib "vba6" (ByVal hProj As Long, ByVal bstrName As Long, ByRef bstrId As Long) As Long
  5. Private Declare Function TipGetLpfnOfFunctionId Lib "vba6" (ByVal hProject As Long, ByVal bstrId As Long, ByRef lpAddress As Long) As Long
  6. Private Declare Sub SysFreeString Lib "oleaut32" (ByVal lpbstr As Long)
  7. Private Const PAGE_EXECUTE_READWRITE = &H40
  8. ' Пример вызова функции по указатею
  9. Public Sub Main()
  10. ' Пропатчиваем функции, перед первым вызовом
  11. PatchFunc "Proto1", AddressOf Proto1
  12. PatchFunc "Proto2", AddressOf Proto2
  13. MsgBox Proto1(AddressOf Func1, 1, "Вызов")
  14. MsgBox Proto1(AddressOf Func2, 2, "По указателю")
  15. MsgBox Proto1(AddressOf Func3, 3, ";)")
  16. Call Proto2(AddressOf Sub1)
  17. Call Proto2(AddressOf Sub2)
  18. End Sub
  19. ' Прототип функций
  20. Private Function Proto1(ByVal Addr As Long, ByVal x As Long, y As String) As String
  21. End Function
  22. Private Sub Proto2(ByVal Addr As Long)
  23. End Sub
  24. ' Функции
  25. Private Function Func1(ByVal x As Long, y As String) As String
  26. Func1 = "Func1_" & y
  27. End Function
  28. Private Function Func2(ByVal x As Long, y As String) As String
  29. Func2 = "Func2_" & y
  30. End Function
  31. Private Function Func3(ByVal x As Long, y As String) As String
  32. Func3 = "Func3_" & y
  33. End Function
  34. Private Sub Sub1()
  35. MsgBox "Sub1"
  36. End Sub
  37. Private Sub Sub2()
  38. MsgBox "Sub2"
  39. End Sub
  40. ' Вспомогательные функции
  41. Private Sub PatchFunc(FuncName As String, ByVal Addr As Long)
  42. Dim lpAddr As Long, hProj As Long, sId As Long, InIDE As Boolean
  43. Debug.Assert MakeTrue(InIDE)
  44. ' Получаем адрес функции
  45. If InIDE Then
  46. EbGetExecutingProj hProj
  47. TipGetFunctionId hProj, StrPtr(FuncName), sId
  48. TipGetLpfnOfFunctionId hProj, sId, lpAddr
  49. SysFreeString sId
  50. Else
  51. lpAddr = GetAddr(Addr)
  52. VirtualProtect lpAddr, 8, PAGE_EXECUTE_READWRITE, 0
  53. End If
  54. ' Записываем вставку
  55. ' Запускать только по Ctrl+F5!!
  56. ' pop eax
  57. ' pop ecx
  58. ' push eax
  59. ' jmp ecx
  60. GetMem4 &HFF505958, ByVal lpAddr
  61. GetMem4 &HE1, ByVal lpAddr + 4
  62. End Sub
  63. Private Function GetAddr(ByVal Addr As Long) As Long
  64. GetAddr = Addr
  65. End Function
  66. Public Function MakeTrue(ByRef bvar As Boolean) As Boolean
  67. bvar = True: MakeTrue = True
  68. End Function
Вызов метода класса (как вычислить адреса напишу позже).
Листинг программы
  1. ' Пример вызова метода по указатею
  2. Public Sub Main()
  3. Dim lpFunc As Long, Obj As Class1, ret As Long
  4. Set Obj = New Class1
  5. GetMem4 ByVal ObjPtr(Obj), lpFunc
  6. GetMem4 ByVal lpFunc + &H1C, lpFunc
  7. PatchFunc "Class1_ZZZ", AddressOf Class1_ZZZ
  8. Call Class1_ZZZ(lpFunc, Obj, 123, 567, ret)
  9. End Sub
  10. ' Прототип функций
  11. Private Function Class1_ZZZ(ByVal Addr As Long, ByVal Obj As Class1, ByVal o As Long, ByVal b As Long, ret As Long) As Long
  12. End FunctionPublic Function ZZZ(ByVal o As Long, ByVal b As Long) As Long
  13. MsgBox o & " " & b
  14. ZZZ = 5
  15. End Function
Вызов API функций:
Листинг программы
  1. ' Пример вызова метода по указатею
  2. Public Sub Main()
  3. Dim hUser As Long, hGDI As Long
  4. Dim DC As Long
  5. hUser = LoadLibrary("user32")
  6. hGDI = LoadLibrary("gdi32")
  7. PatchFunc "GetDC", AddressOf GetDC
  8. PatchFunc "ReleaseDC", AddressOf ReleaseDC
  9. PatchFunc "Ellipse", AddressOf Ellipse
  10. DC = GetDC(GetProcAddress(hUser, "GetDC"), 0)
  11. Ellipse GetProcAddress(hGDI, "Ellipse"), DC, 0, 0, 500, 500
  12. ReleaseDC GetProcAddress(hUser, "ReleaseDC"), 0, DC
  13. End Sub
  14. ' Прототип функций
  15. Private Function GetDC(ByVal Addr As Long, ByVal hWnd As Long) As Long
  16. End Function
  17. Private Function ReleaseDC(ByVal Addr As Long, ByVal hWnd As Long, ByVal hdc As Long) As Long
  18. End Function
  19. Private Function Ellipse(ByVal Addr As Long, ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
  20. End Function

Решение задачи: «Вызов любых функций по указателю»

textual
Листинг программы
  1. Option Explicit
  2.  
  3. Dim WithEvents Component As VBControlExtender
  4. Event ObjectEvent(Info As EventInfo)

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

15   голосов , оценка 4.067 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы