Запуск процедуры из внешней DLL

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Гость

Сообщение Гость »

Здравствуйте ,

Кто имеет опыт подключения внешних DLL
Clarion 5b, ABC, Legacy:

После завершения работы процедуры ExternalProcedure@FSB из
TESTDLL.DLL (Clarion)
аварийное завершение: 'Программа выполнила недопустимую операцию и
будет закрыта' (ошибка в стироке ^^^^^^^^^^^).

Ошибка возникает в случае если завершается
последняя(единственная) копия процедуры (ExternalProcedure@FSB)
и если процедура содержит Browse. Если процедура простое окно
нормальное завершение процедуры FreeLibrary.

КАК ЭТО ПОБОРОТЬ ?

Запуск осуществляется в отдельном процессе:

Код: Выделить всё

TGroup            GROUP
NumThread            BYTE
PathDb               STRING(64)
                   END
 ...
 TGroup = Thread()
 PathDb = 'TBASE.TPS'
 
 START(StartExtProc,,'TESTDLL.DLL','ExternalProcedure@FSB',TGroup)
 ...

!-----------------------------------------------------------------------------
!  Вызов внешней процедуры 
!-----------------------------------------------------------------------------
StartExtProc  PROCEDURE(STRING DllName, STRING ProcName, STRING ParGroup)

L:DLLName          CString(255)
L:DllNamePtr       ULONG
L:DLLInstance      ULONG

L:ProcName         CString(255)
L:ProcNamePtr      ULONG
L:ProcPtr          LONG
L:Result           LONG

L:Group            GROUP
NumThread            BYTE
PathDb               STRING(64)
                   END
 CODE
    L:Group       = ParGroup

    L:DLLName     = DllName
    L:DllNamePtr  = Address(L:DLLName)
    L:DLLInstance = LoadLibrary(L:DllNamePtr)

    IF L:DLLInstance = 0 Then
      Message('Не найдена DLL:' & Clip(L:DLLName))
    ELSE
      L:ProcName    = ProcName
      L:ProcNamePtr = Address(L:ProcName)
      L:ProcPtr     = GetProcAddress(L:DLLInstance, L:ProcNamePtr)

      IF L:ProcPtr = 0
         Message('Не найдена процедура - ' & Clip(L:ProcName))
      ELSE
        CallAddr(L:ProcPtr,L:Group)
      END

      L:Result = FreeLibrary(L:DLLInstance)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    END
--
С уважением!,
Селин_К.Е. mailto:kada@adm.kaluga.ru
Написал: ClaList(2)
Гость

Сообщение Гость »

А приложение-то, на основе которого делался этот браузер, поди,
ABC-шное? и глобальные классы типа обработчика ощибок врядли там будут
инициализированы... (это я так - по памяти, не заглядывая в ABC-код)
КАК ЭТО ПОБОРОТЬ ?
А не пробовал сделать рабоче-крестьяский браузер - в смысле на легаси?
Лично у меня таких проблем никогда не было - любая процедура
запускалась и управление возвращалось без проблем.

--
Best regards,
Vadym mailto:vadim@softcreator.com
ICQ: 82308757
Написал: ClaList(2)
Гость

Сообщение Гость »

А приложение-то, на основе которого делался этот браузер, поди,
ABC-шное? и глобальные классы типа обработчика ощибок врядли там будут
инициализированы... (это я так - по памяти, не заглядывая в ABC-код)
Точно ABC, (С5b), тестовый пример в этом письме
А не пробовал сделать рабоче-крестьяский браузер - в смысле на легаси?
Лично у меня таких проблем никогда не было - любая процедура
запускалась и управление возвращалось без проблем.
Ну это попробовать можно, только хочется именно на ABC.
Кроме того обнаружились проблемы при загрузке DLL у клиента под Win ME
Edition.

Код: Выделить всё

    L:DLLName     = DllName
    L:DllNamePtr  = Address(L:DLLName)
    L:DLLInstance = LoadLibrary(L:DllNamePtr)

    IF L:DLLInstance = 0 Then
      Message('Не найдена DLL:' & Clip(L:DLLName))
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...
--
Best regards,
Селин_К.Е.

А это говорит о том, что DLL вызывает какой-то другой DLL, который и не найден...

---------------------------------------
C уважением,
Юрий Философов,
Главный программист
Корпорация "Диполь", Саратов
E-mail yufil@tacis-dipol.ru (служ)
yufil@mail.ru (дом)
ICQ# 75924439
Написал: ClaList(2)
Гость

Сообщение Гость »

Косяк очевиден - неверно объявлен прототип FreeLibrary, вместо:
FreeLibrary PROCEDURE(ULong),Bool,Raw,Pascal
нужно:
FreeLibrary PROCEDURE(USHORT),PASCAL
Ну и вызов этой процедуры сответвенно подправить, заменить :
L:Result = FreeLibrary(L:DLLInstance)
на
FreeLibrary(L:DLLInstance)
Все работет - аж гай шумит :-)
Кроме того обнаружились проблемы при загрузке DLL у клиента под Win ME
Edition.

Код: Выделить всё

     L:DLLName     = DllName
     L:DllNamePtr  = Address(L:DLLName)
     L:DLLInstance = LoadLibrary(L:DllNamePtr)

     IF L:DLLInstance = 0 Then
       Message('Не найдена DLL:' & Clip(L:DLLName))
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     ...
А этого уродца (я об Me) просто нужно игнорировать - на нам чуть
копнешь в глыбь API - так сразу все теряет работоспособность.
Серьезно...

--
Best regards,
Vadim

(Добавление)

HMODULE это все таки UNSIGNED :)
И PROC в прототип добавить... :p

Алексей,
начальник отдела ПТО
ООО "ОРК"

mail: alex@jrcn.donetsk.ua, icq: 62605472
www: http://atinet.hypermart.net
http://www.nikasoft.co.uk
http://www.clarionline.h1.ru (FAQ-онлайн)
irc: irc.lucky.net:6669, channel #clarion, Bambino
origin: Женщины и фрукты со временем портятся.
Косяк очевиден - неверно объявлен прототип FreeLibrary, вместо:
FreeLibrary PROCEDURE(ULong),Bool,Raw,Pascal
нужно:
FreeLibrary PROCEDURE(USHORT),PASCAL
Не соглашусь
Активно юзаю динамические подгрузки библиотек и косяков не наблюдал:
для 32 bit модели:

LoadLibrary(*CSTRING),UNSIGNED,PASCAL,RAW,NAME('LoadLibraryA')
FreeLibrary(UNSIGNED),BOOL,PASCAL,PROC
GetProcAddress(UNSIGNED,*CSTRING),LONG,PASCAL,RAW

MSDN:
BOOL FreeLibrary(
HMODULE hModule
);


Andrew Myalin
andrew@arsis.ru
ICQ: 10659412
Yahoo group: clarion@yahoogroups.com


(Добавление)

Hello, Vadim!

Спасибо за совет помогло !!!! :up:

--
Best regards,
Селин_К.Е.
Написал: ClaList(2)
Гость

Сообщение Гость »

MSDN:
BOOL FreeLibrary(
HMODULE hModule
);
Давай по порядку - вначале форма, потом суть.

Так вот форма:
Был задан вопрос. В течение суток ответа никто не соизволил дать (хотя
автор даже пример проявления косяка дал). У меня появилась минутка - я
загрузил апкликуху, исправил, проверил и отослал ответ.
И тут сразу же толпа (толпа - понятие несчетное, 2 чела - тоже толпа)
хором побежали доказывать, что я дурак. Ну ладно бы сами попробовали
мои исправления кода, убедились бы они не дают нужного результата -
прога все равно падает и написали бы после этого... но ведь никто
ничего не проверял!! Просто так - пнуть мимо ходом...
А ведь мой код был совршенно рабочий - автор вопроса подтвердил.

А теперь по содержанию.
Ребята, возьмите _свои_ предлагаемые исправления и вставьте в тот
авторский пример и соберите в указаной автором среде. Вы будете, видимо,
сильно удивлены результатом...
Если у кого-то из вас не осталось оригинала вопроса - могу выслать.

P.S. Замечаю, что многим интереснее обсуждать чужие решения, а не
предлагать свои. Это не касается данных конкретных людей - ничего
личного.


P.P.S. Пожалуй и сам я такой.

--
Best regards,
Vadym

(Добавление)
P.P.S. Пожалуй и сам я такой.
:)
Вадим, мы все тут такие, так что лучше нервы побереги.
:)

--
Best regards,
Maxim Yemelyanov

(Добавление)

Я посмотрел пример и что увидел:
Прототипы я привел правильные, т к активно данные механизмы юзаю
То что ты быстро ответ нашёл, моё мнение, ты ушёл от ошибки (прототип
неверный, FreeLibrary просто не сработала),
попробуй в том же примере с моими прототипами загрузить сразу два Browse,
потом закрой один из них, GPF а нету, при попытке закрыть последний Browse -
GPF, получается так что библиотека сама выгружается, скорее всего, если она
загружается в новом потоке, как показано в примере.

Я поглядел в диспечер задач, библиотека выгружается

по хорошему надо грузить библ отдельно от START

Опять же, это моё мнение.

Andrew Myalin
Написал: ClaList(2)
Гость

Сообщение Гость »

Создав простой пример, я падения не увидел.
Две мысли в голове родились - либо где то руки (я писал о прототипах), либо
это ABC.

НО детально расмотрев проблему я вычислил в чём дело.

Очень интересная картина получается

Если в загружаемой Dll'ке есть хотя бы одно обращение к PROP: к файлу, то
GPF при выгрузке обеспечен.

в прилагаемом примере проект dll'ки и проект .exe'шника.
если в .dll в процедуре Prop2 в начале закоментарить DllBase{PROP:Name} то
GPF'а при выгрузке нету, иначе есть.

Может у кого есть идеи на этот счёт?
проверялось на C5, C5.5 - эффект одинаковый

В вашем примере - это ABC, там инициализируются FileManager объекты с кучей
PROP'ов.

Ещё, в примере показано, как в одном .CLW раскрутить LONG (полученный от
GetProcAddress) в прототип функции
или процедуры любой струткуры, для дальнейшего использования.
Данный механизм когда то уже обсуждался в ClaList'е.

Код: Выделить всё

            MAP
                 Proc2Type(STRING),TYPE
                 MODULE('')
                  RunProc2(LONG,STRING),NAME('RunProc2')
                 END
                  RunProc2(Proc2Type,STRING),NAME('RunProc2')
                END
            END
loc_AddressProcedure        LONG
        CODE

 !Реализуем вторую, вызываем первую.
 RunProc2(loc_AddressProcedure,'Hello!')


RunProc2            PROCEDURE(Proc2Type Proc,STRING Param)
    CODE

 Proc(Param)
Andrew Myalin

(Добавление)

А у меня работает... И ABC ... Правда, не пользуюсь функциями API.
В Dll с описанием файлов описываю глобальную очередь

Код: Выделить всё

ProcQ   Queue
ProcName Cstring(32) 
Addr      Ulong
             End        
И две процедуры - добавления записи в очередь и поиска в очереди

RegisterProc ('ProcName',Addr) - добавляет запись
GetProcAddr ('ProcName') - возвращает адрес

1. DLL загружаю по Call(DllName,'Init@F',1)
2. Внутри Dll размещаю Source-процедуру Init, которая дописывает адреса процедур в глобальную очередь вызовом функции

RegisterProc ('ProcName',Address(Procedure)) .

Там же решается и проблема с инициализацией DLL под CW6 .

А дальше приложение просто находит в очереди адрес процедуры и стартует её...

Код: Выделить всё

        
      Map 
      START(Long,UNSIGNED=0),SIGNED,PROC,NAME('Cla$START')
      START(Long,UNSIGNED=0,STRING),SIGNED,PROC,NAME('Cla$START1')
      START(Long,UNSIGNED=0,STRING,STRING),SIGNED,PROC,NAME('Cla$START2')
      START(Long,UNSIGNED=0,STRING,STRING,STRING),SIGNED,PROC,NAME('Cla$START3')
     End 

     Start(ProcAddress,,Param1,Param2) 
Когда Dll не нужен, его можно и выгрузить по Unload

---------------------------------------
C уважением,
Юрий Философов,
Главный программист
Корпорация "Диполь", Саратов
E-mail yufil@tacis-dipol.ru (служ)
yufil@mail.ru (дом)
ICQ# 75924439
Написал: ClaList(2)
Ответить