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

Здесь можно найти готовые «кирпичики» — части кода, пригодные для построения более крупных проектов, а также решения различных типовых и не очень задач на VB.

Модератор: Brickgroup

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

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

Сообщение Хакер » 28.02.2011 (Пн) 21:31

Обсуждение проекта, замысла, идеи, эмоции по поводу — в этой теме, пожалуйста.
В данной теме публикуются последние версии кирпича, обсуждаются конкретные вопросы, сообщают о багах.

( :!: Пожалуйста, заходите в эту тему хотя бы раз в месяц, если вы используете модуль в своих проектах, чтобы посмотреть, не вышла ли новая версия :!: )

Последняя версия:
func_pointers_1.0.4.zip
Модуль и пример. (Версия 1.0.4)
(11.74 Кб) Скачиваний: 383


    Устаревшие версии:
    func_pointers_1.0.2.zip
    Модуль и пример. (Версия 1.0.2) Содержит ошибку!
    (11.2 Кб) Скачиваний: 208

    func_pointers_1.0.1.zip
    Модуль и пример. (Версия 1.0.1) Содержит ошибку!
    (10.94 Кб) Скачиваний: 156

    func_pointers.zip
    Модуль и пример. (Версия 1.0.0) Содержит ошибку!
    (10.57 Кб) Скачиваний: 159


Модуль позволяет вам объявлять типизированные указатели на функции и делать вызов через эти указатели. Типизированный — значит вы указываете прототип (тип возврата, количество и типы всех параметров) функций, на которые будет указывать данный указатель. Считайте, что указатель, это переменная.

Объявляется указатель так:
Код: Выделить всё
[Private|Public] Declare {Sub|Function} <ИмяУказателя> Lib "*" ([аргументы]) [As ТипВозврата]

или так:
Код: Выделить всё
[Private|Public] Declare {Sub|Function} <ИмяПсевдонимаУказателя> Lib "*" Alias "<ИмяУказателя>" ([аргументы]) [As ТипВозврата]


То есть в точности так, как обычная Declare Function, но вместо имени библиотеки вы указываете звёздочку (*).

Присваивание/получение значения указателю/указателя выполняется так:
Код: Выделить всё
FuncPointer("<ИмяУказателя>") = <новое_значение>
<переменная> = FuncPointer("<ИмяУказателя>")


Вызов по указателю осуществляется с тем же синтаксисом, что и вызов обычной функции.

Поддержка таких указателей включается и выключается функцией MagicPointersOnOff.

В архиве содержится сам модуль и проект-пример его использования. Проект-пример состоит из трёх частей:
  • Пример с Апплетами. Мы перебираем в папке «system32» все файлы с расширением «.cpl». Подгружаем каждый CPL-файл и вызываем с помощью указателя экспортируемую функцию CPlApplet. Через её вызов получается список диалогов, предоставляемых апплетами:
    Изображение
    Пример демонстрирует, как с помощью указателей на функции работать с библиотеками-плагинами.
  • Пример с вызовом метода экземпляра класса. Метод созданного экзмемпляра класса вызывается через указатель, этому методу передаётся некоторое значение. Пример показывает возможность вызова через указатели не только Static-функций, но и методов классов (по механизму раннего связывания).
  • Пример с операторами. Адреса двух функций (DoAdd, DoSub), у которых идентичные прототипы, присваиваются указателю MathOperator и выполняется вызов. Выводятся результаты сложения и вычитания одинаковых операндов.
  • Пример с callback-ами. Делается вызов «чужой» процедуры, которой передаётся адрес «нашей» процедуры обратного вызова. Чужая процедура по переданному адресу делает вызов нашего callback'а, чтобы сообщить о каждом из найденных файлов. Показывает реализацию механизма callback-ов.

Примеры сделаны на скорую руку, наверняка я их переделаю.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Вызов функций по указателю

Сообщение Хакер » 06.03.2011 (Вс) 11:30

Загрузил новую версию.
  • Исправлена ошибка.
  • Дополнен пример.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Вызов функций по указателю

Сообщение Хакер » 10.03.2011 (Чт) 14:25

Скачивайте новую версию.
Исправлен баг: обычные Declare-функции, ни разу не вызванные до включения «волшебных указателей», при вызова инициирует крах из-за существования в LocalResolver ветки (по которой может пойти выполнение), которая ничего не возвращает.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1598
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Вызов функций по указателю

Сообщение arthur2 » 10.03.2011 (Чт) 17:04

Вот в этой месте:
Код: Выделить всё
If Err.Number <> 0 Then
    Err.Raise 453, , "Specified pointer is not set."
пропущено on error goto 0, если выполнение заходит сюда, сгенерированная ошибка игнорируется :)
Артур
 
   

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

Re: Вызов функций по указателю

Сообщение Хакер » 10.03.2011 (Чт) 17:25

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

Временный bug-fix:
Найти:
Код: Выделить всё
            On Error Resume Next
            Err.Clear
            lpAddress = m_UndiscoveredPointers(sPointerName)
            If Err.Number <> 0 Then
                Err.Clear
                lpAddress = m_DiscoveredPointers(sPointerName)
                If Err.Number <> 0 Then
                    Err.Raise 453, , "Specified pointer is not set."
                    Exit Function
                End If
            End If
            On Error GoTo 0
           
            If lpAddress = 0 Then

Заменить на:
Код: Выделить всё
            On Error Resume Next
            Err.Clear
            lpAddress = m_UndiscoveredPointers(sPointerName)
           
            If Err.Number <> 0 Then
                On Error GoTo 0
                On Error Resume Next
                lpAddress = m_DiscoveredPointers(sPointerName)
                If Err.Number <> 0 Then
                    On Error GoTo 0
                    Err.Raise 453, , "Specified pointer is not set."
                    Exit Function
                End If
            End If
           
            If lpAddress = 0 Then
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Вызов функций по указателю

Сообщение djalex777 » 23.05.2011 (Пн) 16:49

Вызов методов класса, определенных как function вызывает крах приложения. Это так и должно быть?

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

Re: Вызов функций по указателю

Сообщение Хакер » 24.05.2011 (Вт) 3:46

Нет, что-то неправильно делаешь.
В примере же даже есть суб-пример:
Хакер писал(а):# Пример с вызовом метода экземпляра класса. Метод созданного экзмемпляра класса вызывается через указатель, этому методу передаётся некоторое значение. Пример показывает возможность вызова через указатели не только Static-функций, но и методов классов (по механизму раннего связывания).
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Вызов функций по указателю

Сообщение Хакер » 24.05.2011 (Вт) 6:40

Если включить телепатию, получается, что вероятно ты просто забыл, что все методы (и Sub-ы и функции) возвращают HRESULT, а у функции формальное возвращаемое значение передаются через физический последний ByRef-параметр.

То есть указатель на функцию, возвращающую Long, надо объявлять так:
Код: Выделить всё
Declare Function ptr lib "*" (byval This As CYourClass, ByRef relval as Long) As Long
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Вызов функций по указателю

Сообщение djalex777 » 24.05.2011 (Вт) 11:21

Ааай, точно, затупил. Спасибо!

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

Re: Вызов функций по указателю

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

Не за что.

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

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Вызов функций по указателю

Сообщение djalex777 » 24.05.2011 (Вт) 13:11

Я его просто смотрел, так что цели, как таковой, не было :)

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

Re: Вызов функций по указателю

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

Вопрос (всем): стоит ли добавлять возможность связать сам указатель с переменной, чтобы устанавливать указатель не так: FuncPointer("ptr1") = 123, а так v_ptr1 = 123? Само по себе связывание будет выполняться один раз, а последующее присвоение — сколько угодно раз.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

0xy
Бывалый
Бывалый
 
Сообщения: 223
Зарегистрирован: 14.06.2006 (Ср) 2:34

Re: Вызов функций по указателю

Сообщение 0xy » 02.10.2011 (Вс) 23:48

Баг в примере:
frmApplets:Form_Load падает на "fn = Dir()" (3-я строка снизу).
Падение происходит по причине отсутствия искомых файлов *.cpl в папке System32.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1873
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Вызов функций по указателю

Сообщение ger_kar » 07.10.2011 (Пт) 9:50

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

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

Re: Вызов функций по указателю

Сообщение Хакер » 30.03.2012 (Пт) 20:14

Опубликовал исправленную версию.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 3796
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Вызов функций по указателю

Сообщение Mikle » 01.04.2012 (Вс) 19:32

Класс. Буду пользоваться. Только добавил во все модули "Option Explicit" :roll: и переименовал безликую ф-цию "L_" в "PtrToLong".
Вопросы:
1. Там используется "On Error", допустимо ли, используя такие указатели, применять все дополнительные опции оптимизации? Я скомпилировал, вроде работает, но мало ли.
2. Есть ли преграды для выполнения заранее скомпилированных, скажем, на ассемблере процедур, загруженных в виде ресурса? Или это будет попытка выполнения данных?

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

Re: Вызов функций по указателю

Сообщение Хакер » 01.04.2012 (Вс) 20:34

Mikle писал(а):и переименовал безликую ф-цию "L_" в "PtrToLong".

Ну и неправильно. Правильно переименовать CastAsLong. Или ты имел в виду PtrAsLong? Тогда допустимо. Но L_ лучше ибо коротко. Я поклялся себе не писать строки длиннее 83 символов кроме исключительных случаев.

Mikle писал(а):1. Там используется "On Error", допустимо ли, используя такие указатели, применять все дополнительные опции оптимизации? Я скомпилировал, вроде работает, но мало ли.

По идее допустимо. Оптимизации, отключающие проверки, могут привести к тому, что программа упадёт, если проверка не сделана вручную там, где надо. Но так она упадёт в любом случае, и без моего кирпича, и с ним.

Mikle писал(а):2. Есть ли преграды для выполнения заранее скомпилированных, скажем, на ассемблере процедур, загруженных в виде ресурса? Или это будет попытка выполнения данных?

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

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 3796
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Вызов функций по указателю

Сообщение Mikle » 01.04.2012 (Вс) 21:03

Хакер писал(а):Правильно переименовать CastAsLong. Или ты имел в виду PtrAsLong? Тогда допустимо.

Приведение пойнтера к лонгу, по аналогии с FtoDW.
Хакер писал(а):Я поклялся себе не писать строки длиннее 83 символов кроме исключительных случаев.

А я - не называть Public сущности непонятно :)
Хакер писал(а):если проверка не сделана вручную там, где надо. Но так она упадёт в любом случае, и без моего кирпича, и с ним.

Это понятно, главное - на работе кирпича не скажется.
Хакер писал(а):помещать их в ресурсы — неправильно. Но если дать ресурсам E-атрибут, то можно.

А как правильно? Или как "дать ресурсам E-атрибут"?

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

Re: Вызов функций по указателю

Сообщение Хакер » 02.04.2012 (Пн) 0:47

Mikle писал(а):Приведение пойнтера к лонгу, по аналогии с FtoDW.

Так ведь нет никакого поинтера. AddressOf возвращает Long, но обязан быть аргументом какой-нибудь функции. Поэтому это функция-пустышка, чтобы выполнить это ерундовое требование.

Mikle писал(а):А как правильно?

По идее, правильно, чтобы код был в секции кода. Даже инородный код туда можно легко засунуть, но на порядок сложнее «получить его адрес». Хотя стоп. Это если говорить о нашей собственной секции кода. Но ведь можно и в чужую. Так что очень правильный метод — положить написанные в на ассемблере процедурки в DLL, подгружать эту DLL и вызывать нужные процедурки по указателю. Правда тут уже и указатели не нужны, можно вызывать через обычный Declare. Хотя именно указатели могут потребоваться чтобы воспользоваться удобствами именно самих указателей (а не для того, чтобы вызвать что-то, что раньше вообще никак вызвать было нельзя*)

Второй по правильности способ — копировать код в выделенные фрагменты, обладающие E-флагом. Выделенные с помощью VirtualAlloc/HeapAlloc.

Mikle писал(а):Или как "дать ресурсам E-атрибут"?

Всей секции можно дать с помощью утилиты (входящей в VS) editbin. Примерно так: editbin /section:.rsrc,re my.exe.
Отдельно взятой странице — с помощью VirtualProtect.

Но как ты собрался лёгко из VB получать адрес бинарного ресурса?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 3796
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Вызов функций по указателю

Сообщение Mikle » 02.04.2012 (Пн) 9:48

Хакер писал(а):Но как ты собрался лёгко из VB получать адрес бинарного ресурса?

Можно через костыль - поиск по уникальному идентификатору, можно выполнить LoadResData в массив, который предварительно перенаправлен на область памяти, выделенную через VirtualAlloc/HeapAlloc.
Но как CallWindowProc выполняет код в области данных?

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

Re: Вызов функций по указателю

Сообщение Хакер » 02.04.2012 (Пн) 9:55

Mikle писал(а):Но как CallWindowProc выполняет код в области данных?

Никак не выполняет. Программы, пытающиеся сделать это, падают с DEP-исключением. Если аппаратный DEP поддерживается процессором, плюс включен, плюс программа не сидит в исключениях.

Плюс, ещё есть SetProcessDEPPolicy, но это всё равно, что признавать — я, автор этой программы, — криворукий неандерталец, не признающий DEP.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 3796
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Вызов функций по указателю

Сообщение Mikle » 02.04.2012 (Пн) 11:41

Разобрался в том примере, перед CallWindowProc выполняли VirtualProtect Lib "kernel32".

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2751
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 08.07.2013 (Пн) 18:46

Требуются ли какие-либо изменения этого модуля для использования в новых версиях Офиса? В частности интересует 2013й Visio.

А то я тут набрёл на вот такое объявление функции:
Код: Выделить всё
#If Win64 Then
    #If VBA7 Then    ' Windows x64, Office 2010
        Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32.dll" Alias _
                                "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As LongLong
    #Else    ' Windows x64,Office 2003-2007
        Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
                                "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As LongLong
    #End If
#Else
    #If VBA7 Then    ' Windows x86, Office 2010
        Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32.dll" Alias _
                                "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
    #Else    ' Windows x86, Office 2003-2007
        Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
                                "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
    #End If
#End If
соответственно возникла мысль, что функции, используемые тут тоже надо объявлять как-то так...

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

Re: Вызов функций по указателю

Сообщение Хакер » 09.07.2013 (Вт) 3:03

Qwertiy писал(а):Требуются ли какие-либо изменения этого модуля для использования в новых версиях Офиса?

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

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1873
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Вызов функций по указателю

Сообщение ger_kar » 09.07.2013 (Вт) 7:46

Декларация судя по приведенному коду изменилась для некоторых случаев. А после прочтения
http://msdn.microsoft.com/ru-ru/library/office/gg278581.aspx
http://msdn.microsoft.com/ru-ru/library/office/gg278832.aspx
Появилось убеждение, что в 64 разрядном варианте вызов по указателю работать без переделки не будет.
А вот проверить на практике мне не представляется возможным.
Бороться и искать, найти и перепрятать


Вернуться в Кирпичный завод

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

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

    TopList