Не могу вызывать ф-и API из Callback ф-и
, Есть Callback функция через AddressOf...
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.141] |
|
|
Правила раздела Visual Basic: Общие вопросы
FAQ Сайта
FAQ Раздела
Кладовка
Наши Исходники
API-Guide
Поиск по Разделу
MSDN Library Online
Google
Не могу вызывать ф-и API из Callback ф-и
, Есть Callback функция через AddressOf...
|
Сообщ.
#1
,
|
|
|
|
Я пользуюсь некой DLL через Declare. Эта DLL требует инициализации с передачей ей (через AddressOf) указателя на мою Callback-функцию (на VB), которую эта DLL будет дергать в неопределенные моменты. Пока все ясно. Проблема в том, что я не могу размещать внутри моей Callback-функции никакие вызовы API-функций - происходит крах. Дополнительно сообщю, что DLL написана не мной на С++, публичные вызовы по StdDecl. Как говорят в KB198607 ( http://support.microsoft.com/kb/q198607/ ), виновата несовместимая реализация потоков. Но решения там нет.
Вот в сильно упрощенном виде код: ![]() ![]() ' Здесь я объявляю функцию инициализации DLL Public Declare Function init_DLL Lib "XXX.dll" (ByVal CallbackFunc As Long) As Long ' Это типа точка входа Public Sub Main() ' Инициирую DLL с передачей ей указателя на мою Callback-функцию init_DLL(AddressOf CallbackFunc) End Sub ' А вот и сама Callback-функция в соответствием с требованием DLL Public Function CallbackFunc(ByVal param1 As Long, ByVal param2 As Long) As Long ' невозможно делать вызовы API-функций End Function Неуклюжее рабочее решение - поставить таймер, который откладывает выполнение асинхронной функции (вместо нее будет вымолняться другая, синхронная ф.) Но мало того, что это не красиво, моя callback функция не сможет возвращать осмысленного значение, т.к. выход из нее раньше, чем собственно выполнение. Как жить-то дальше? |
|
Сообщ.
#2
,
|
|
|
|
похоже это действительно ваш случай.
а стандартные вба функции все работают в таком коллбаке? если ваш - то не должны бы все. скорее "почти никакие" ... если не ваш случай, то может быть этой "XXX.dll" сделать LoadLibrary до вызова init_DLL (?) ... попробуйте нужную апи функцию вызвать предварительно до инициализации внешней библиотеки. (или использовать tlb-описатель для задействованных таким образом библиотек) ... если случай все же ваш, и ваш VB-код действительно исполняется потоком, который вб не сам для себя создал (а очень похоже по сказанному), то, как минимум, нужно инициализировать оле для этого ( в этом) потоке и создать вручную однопоточные ком-апартаменты. (с вытекающей потом терминацией поднятого при завершении потока) показать как "надо" - не смогу. так не делал никогда. "книжные знания". |
|
Сообщ.
#3
,
|
|
|
|
Jupiter
Попробуй другой способ работы с потоками..... |
|
Сообщ.
#4
,
|
|
|
|
Цитата а стандартные вба функции все работают в таком коллбаке? если ваш - то не должны бы все. скорее "почти никакие" Я могу работать с глобальными и модульными переменными. Вызовы функций VB происходят странно - в основном падает. Даже на On Error GoTo. При этом есть разница, запускаю ли я скомпилированный ехе, или из ide. Все описанные здесь рекомендации вызывают у меня ужас. В настоящее время я пишу на С свойю dll-переходник к этой чужой dll в надежде, что оттуда Callback будет работать нормально. Ну а уж свою-то dll со своей же vb-программой я подружить всегда смогу :-) Хотя обидно: я столько преодалел, чтобы заставить эту dll работать непосредственно из-под vb, будь он проклят. |
|
Сообщ.
#5
,
|
|
|
|
советы вызывают ужас?
значит - написать переходник на си - легче, чем загрузить библиотеку до вызова коллбэк функции? вам видней. но коллбек сам по себе от этого вряд ли заработает. может, все-таки - попробовать loadlibrary сначала? -- а что вас заставляет вообще мучаться с vb? |
|
Сообщ.
#6
,
|
|
|
|
2сразу все: А немогли бы Вы описать, каким образом приведенное вами решение позволит "подружить" VB с многопоточностью?
|
|
Сообщ.
#7
,
|
|
|
|
Цитата Velin @ 2сразу все: А немогли бы Вы описать, каким образом приведенное вами решение позволит "подружить" VB с многопоточностью? Там решение такое. Сообщения, посылаемые через Callback (а это именно механизм сообщений) помещаются в буфер внутри моей переходной dll. А VB-программа переодически (увы, по таймеру) синхронно опрашивает эту dll. Многопоточность, если она есть, существует между моей и чужой dll-ми, там все на мьютексах, как и положено. А VB ничего об этом не знает. Такой механизм уже много лет работает для другого источника сообщений. Самому мне вся эта кухня с таймерами не очень нравится. Но пока не перейдем на .net, похоже так и будем в муках изобретать (рожать) велосипеды. |
|
Сообщ.
#8
,
|
|
|
|
2 Vellin
если вы о loadlibrary, то: пока нет ясных оснований считать, что дело именно в многопоточности. пока ясно, что загрузка (и инициализация) dll происходит в момент первого обращения к объявленной через декларе функции. И "предложение" заключается просто в разведении загрузки и инициализации длл от первого обращения к ней за исполнением функции. Это единственное, что я могу определенно вынести непосредственно из первоначально сказанного. Из продолжения может возникать подозрение, что идет какое-то косвенное субклассирование чужого окна. Но чего-то внятного сказать нельзя. Предположение о том, что эта длл передает "чужому" уже существующему на момент передачи потоку адрес функции, которая потом должна быть быполнена в том другом потоке - тоже вполне возможно. и слова некоторые на эту мысль наводят. Если да - то далее идут слова про исполнение вб кода в "чужих" потоках, которые не были созданы системой поддержки исполнения вб-кода. Однако, если нет информации и инструменария понять, что в точности происходит, то идти надо от простых предположений. (так я думаю) |
|
Сообщ.
#9
,
|
|
|
|
а вы не пробовали вызывать API функции динамически, т.е. без ее предварительной декларации ?
|
|
Сообщ.
#10
,
|
|
|
|
как связано с дружением с многопоточностью:
Цитата попробуйте нужную апи функцию вызвать предварительно до инициализации внешней библиотеки. само по себе это мимо кассы. поторопился. Цитата (или использовать tlb-описатель для задействованных таким образом библиотек) это позволит иметь "нормально" построенный вызов апи функции. адрес которой гарантированно известен (на этапе компиляции) в момент вызова. а нужная длл будет гарантирована загружена в адресное простанство программы в момент старта (загрузки). Код вызова апи функции полностью сформирован и не требует поддержки времени выполнения. все имеет хорошие шансы срастись. чужой поток будет иметь дело с кодом не требующим поддержки в момент вызова от среды вб. есть шансы, что все срастется. ... Цитата если случай все же ваш, и ваш VB-код действительно исполняется потоком, который вб не сам для себя создал (а очень похоже по сказанному), то, как минимум, нужно инициализировать оле для этого ( в этом) потоке вб почти 100-процентно полагается на ком. почти все (по крайней мере - все видимые в просмотрщике объектов) функции вб не будут работать, если в исполняющем потоке не инициализирован ком. единственный шанс получить минимально способный к выполнению относительно сложного вб-кода не вб поток - инициализировать в этом потоке ком (типа - олеинитиалайз) Цитата и создать вручную однопоточные ком-апартаменты. (с вытекающей потом терминацией поднятого при завершении потока) так делает сам вб для каждого "своего" потока. говорят, "в принципе" это можно обойти. но лучше следовать его примеру. Цитата показать как "надо" - не смогу. так не делал никогда. "книжные знания". тут вроде пояснять нечего. я - не делал. |
|
Сообщ.
#11
,
|
|
|
|
2 SCINER
про динамический вызов. очень может даже быть что прокатит. нужно только придумать какой-то надежный механизм сохранения параметров вызова для вызывающей процедуры. где-нибудь в атомах и/или оконных лонгах. думаю, что это "потребует кодирования". и как по мне - лучше уж описатель прикрутить. |
|
Сообщ.
#12
,
|
|
|
|
еще про динамический вызов.
думаю, что так или иначе, код динамического вызова (задействованных в вызове апи-функций) надо строить на tlb. |
|
Сообщ.
#13
,
|
|
|
|
Цитата пока нет ясных оснований считать, что дело именно в многопоточности По Вашему http://support.microsoft.com/kb/q198607/ это не основание? |
|
Сообщ.
#14
,
|
|
|
|
не основание для чего? я не понял, на какое именно место в статье вы хотите точно указать.
если на это: Цитата This error may occur immediately following a declared API function call within a Visual Basic callback function то я вроде по русски говорю - попробуйте использовать tlb-описатели. и более того - если неизвестно, кто и как создавал тот внешний поток, то никто не обещал не только работоспособности декларированных апи (требующих поддержки времени исполнения), но и "обычного" вб-шного кода. кстати, когда я говорил про предварительный вызов до регистрации функции косвенного выполнения, то думал в первую очередь о том, что в данном конкретном случае совсем не обязательно речь идет о "чужом потоке", а, вполне возможно, об особенностях инициализации конкретной xxx И без всяких потоков бывает, что принудительная предварительная загрузка целевой dll стабилизирует работу декларированных функций. если вы еще раз прочитаете статью, на которую сослались, то увидите, что ни в каком предложении она не входит в противоречие с моими утверждениями. (даже если какие-то из них и окажутся неточными - статья своим текстом их непосредственно не опровергает) |
|
Сообщ.
#15
,
|
|
|
|
>попробуйте использовать tlb-описатели.
Я бы с удовольствием попробовал. Вы только намекните, как именно... В смысле, о чем идет речь в терминах синтаксиса VB? |
|
Сообщ.
#16
,
|
|
|
|
я не понял последнего предложения.
давайте так: выложите полные точные декларации для ваших функций в проблемной длл и использованных в функции косвенного вызова апи. если их не слишком много окажется (типа - 3-4) выложу вам сегодня описатель. просто закомментируете в проекте свои декларации и подключите описатель |
|
Сообщ.
#17
,
|
|
|
|
tlb описатель - это библиотека типов. Подключается в прект в References
возьми здесь достаточно полные описатели апи-функций как анси WinTlb3.zip так и юникод WinTlbU.zip версий апи-функций. mckinney |
|
Сообщ.
#18
,
|
|
|
|
Попробовал выводить значение GetCurrentThreadID в sub Main и в Callback функции. Они ОТЛИЧАЮТСЯ.
Вот код моей программы на VB ![]() ![]() ' Здесь я объявляю функцию инициализации DLL Public Declare Function init_DLL Lib "XXX.dll" (ByVal CallbackFunc As Long) As Long ' А вот "крутая" функция API. Private Declare Function Beep Lib "kernel32" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long ' Это типа точка входа Public Sub Main() ' Инициирую DLL с передачей ей указателя на мою Callback-функцию init_DLL(AddressOf CallbackFunc) End Sub ' А вот и сама Callback-функция в соответствием с требованием DLL Public Function CallbackFunc(ByVal param1 As Long, ByVal param2 As Long) As Long Beep 1000, 500 ' Бу-бух... Упали... End Function Вот описания на C из чужой документации. Инициализация (init_DLL) происходит нормально. ![]() ![]() DWORD init_DLL (VLSDK_CALLBACK* callback); // Прототип функции обратного вызова typedef int (__stdcall VLSDK_CALLBACK)(DWORD param1, DWORD param2); |
|
Сообщ.
#19
,
|
|
|
|
Цитата Jupiter @ Вызовы функций VB происходят странно - в основном падает. Даже на On Error GoTo. ловить надо с помощью SetUnhandledExceptionFilter см. пример ее использования. Прикреплённый файл Code_Exception.rar (3.87 Кбайт, скачиваний: 70)
|
|
Сообщ.
#20
,
|
|
|
|
Цитата , @ tlb описатель - это библиотека типов. Подключается в прект в References возьми здесь достаточно полные описатели апи-функций как анси WinTlb3.zip так и юникод WinTlbU.zip версий апи-функций. mckinney Спасибо, я скачал. Я понял, в каком направлении все должно крутиться. Чтобы получить требуемый win.tlb я должен запустить некий батник. Не люблю я эти батники: они вечно что-нибудь требуют. Вот и в этот раз: >midl : command line error MIDL1005 : cannot find C preprocessor cl.exe Может быть у Вас есть win.tlb? |
|
Сообщ.
#21
,
|
|
|
|
файл больше 200 кб размером -- прилепить не могу.
где-то он лежал в скомпилированном виде - или на вбакселераторе или на сайте у Петерсона. по всему - из чужого потока вызов происходит. бип может и сработает. или другой одиночный вызов апи. с более содержательными алгоритмами будут проблемы. |
|
Сообщ.
#22
,
|
|
|
|
вот маленький описатель
там только бип и попытка описать вашу функцию инициализации. подключите библиотеку попробуйте сначала закомментировать в своем коде только декларацию бип проверьте, что работает библиотечной описатель в обычной процедурею дальше попробуйте запустить в "рабочем" режиме. попробуйте также закомментировать в свем коде объявление init_DLl. если объявление в библиотеке составлено неверно, то скомпилированный проект не запустится и дело до точки вызова init_dll не дойдет Прикреплённый файл Beep.tlb (1.52 Кбайт, скачиваний: 216)
|
|
Сообщ.
#23
,
|
|
|
|
вот маленький описатель
там только бип и попытка описать вашу функцию инициализации. подключите библиотеку попробуйте сначала закомментировать в своем коде только декларацию бип проверьте, что работает библиотечной описатель в обычной процедурею дальше попробуйте запустить в "рабочем" режиме. попробуйте также закомментировать в свем коде объявление init_DLl. если объявление в библиотеке составлено неверно, то скомпилированный проект не запустится и дело до точки вызова init_dll не дойдет Прикреплённый файл Beep.tlb (1.52 Кбайт, скачиваний: 240)
|
|
Сообщ.
#24
,
|
|
|
|
Цитата Victosha @ вот маленький описатель там только бип и попытка описать вашу функцию инициализации. ... Спасио. Эксперимент состоялся. Но утишительного мало. Действительно, Beep удалось запустить по Вашей схеме. Но из Callback он все равно падает :-( Инициировать длл с помощью даного описателя, к сожалению, невозможно, т.к. для упрощения разговора я опустил еще один аргумент (long), да и имя функции дал более понятное для обсуждения. То есть, если бы я знал, что Вы следаете описание на idl, то конечно бы дал полное описание ф-и инициализации. Все равно, спасибо за поддержку! Буду писать переходник. |