Перейти к содержанию
Fire Monkey от А до Я
  • 0

Что я делаю не так при работе с DLL библиотеками из FireMonkey?


Ethernet

Вопрос

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

 

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

 

Суть проблемы.

Создаю dll библиотеку и сую туда форму со своим функционалом (Delphi, RAD Studio XE5). Динамически подгружаю в приложение и по сути всё работает, но... Когда же я хочу выгрузить приложение я получаю, либо ряд ошибок AV, либо зависание всего приложение при выполнении FreeLibrary, либо неизвестную мне ошибку "DXGI ERROR: CreateDXGIFactory cannot be called from DllMain. [ MISCELLANEOUS ERROR #76: ]".

Так же не могу понять, как передать Handle приложения в библиотеку (в VSL это было довольно просто).

 

К сожалению никакой информации по данным вопросам я не смог найти, кроме не больших вырезок со своими недочётами.

 

Прошу вас помочь в решении данных проблем.

Большое спасибо.

 

С уважением, Ethernet.

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
  • Администраторы

Добрый день,

  1. Работа с DLL в Windows одинакова для всех фреймворков (VCL, FMX) и ни каким образом не зависит от используемого фреймворка (VCL или FireMonkey). 
  2. Только по описанию проблемы тяжело что-то сказать.

Согласно пункту 5 правил нужен тестовый проект, на котором воспроизводится ошибка. Без этого вероятность того, что кто-то вам сможет здесь помочь, увы минимальна...

 

Спасибо

Ссылка на комментарий
  • 0

У меня аналогичная проблема (и не у меня только, судя сколько вопросов с этой бедой на разных форумах). Я так же не нашел причину. Оказалось что тот же код, но с формой VCL прекрасно работает и ничего не падает. Потому для себя я сделал связку: программа на FMX, а dll содержат формы VCL. Благо то, что это не критично (хотя и выглядит не стилизовано).

Изменено пользователем DirtyBorov
Ссылка на комментарий
  • 0

Возможно и бред, но все же: на днях убил больше суток на работу с dll. У меня там графика была, но не суть важно - разрабатывалось в 8, а dll в 1, ибо нужные хедеры появились только в 10. Одним словом - сыпались ошибки и при обращении и при выгрузке, пока не додумался просто проект перенести в 10-ку, все проблемы как рукой сняло. Попробуйте сменить версию среды разработки.

Цитата

Работа с DLL в Windows одинакова для всех фреймворков (VCL, FMX) и ни каким образом не зависит от используемого фреймворка (VCL или FireMonkey). 

Со всем уважением, но зависит (возможно в теории нет) но практике да, в частности при работе с WinApi.

Ссылка на комментарий
  • 0
2 часа назад, Gingercat сказал:

сыпались ошибки и при обращении и при выгрузке,

вы случайно не объекты и/или дельфовые типы (а-ля string) передавали между exe и dll?

Ссылка на комментарий
  • 0
11 часов назад, kami сказал:

вы случайно не объекты и/или дельфовые типы (а-ля string) передавали между exe и dll?

Вы не поверите, но я возвращал из dll TBitmap, созданный на основе surface Desktop Duplication API. Причем, ошибки были именно плавающие - без закономерностей. Иногда вообще access violation вышибало - нервов потратил огого. Причем, первое обращение проходило отлично, все следующие сыпали ошибки. Вот такая оказалась несовместимость версий, хотя не было использовано ничего узкоспециального. За исключением конечно, собственно, самого Desktop Duplication API.

 

Да и к слову: у топикстатртера, судя по CreateDXGIFactory, также работа с Directx - возможно проблема именно в этом. Там есть некоторые хитрости относительно объявлений сущностей. Visual c++ допускает просто объявление, а билдер ругается, ему нужна иннициализация типа = {}. Одним словом не дружим Builder c++ с новыми (особенно) версиями библиотек DirectxX. Но это только предположения.

Изменено пользователем Gingercat
Ссылка на комментарий
  • 0
1 час назад, Gingercat сказал:

Вы не поверите, но я возвращал из dll TBitmap, созданный на основе surface Desktop Duplication API.

Вы не поверите, но передавать экземпляры классов между различными независимыми модулями (будь то exe и dll или две разных длл) нельзя даже если версии IDE абсолютно идентичны. Потому что TBitmap в одном модуле - это не то же самое, что TBitmap в другом модуле. У каждого модуля СВОЙ менеджер памяти, своя таблица виртуальных методов (VMT), свои структуры описания классов и т.д. и т.п. Модуль будет пытаться работать с экземпляром класса, как со своим, обращаясь к своим методам вместо методов, реализация которых находится в другом модуле. И память при работе с методами и свойствами объекта он будет выделять и пытаться освободить СВОЮ, а надо было бы - память, выделенную менеджером памяти другого модуля. Вот вам и первопричина для глюков.

Из dll в exe и наоборот в случае с битмапом вы можете передать максимум hbitmap, поскольку это хендл на ресурс ОС. А классы, их экземпляры, строки и другие типы с управляемым временем жизни передавать нельзя, это табу.

 

Для изучения: http://www.gunsmoker.ru/2011/12/delphi.html#n5  сразу можно переходить к правилу 6

Изменено пользователем kami
Ссылка на комментарий
  • 0

Если все так печально, почему это все работает в пределах одной версии? И вообще - что значит невозможно? Тонны кода работают на передаче именно классов и экземпляров, а вы завляете что это не верно? Или я чего то не понимаю

 

То есть значит:

__declspec(dllexport) TBitmap* __stdcall GetBmpGdi(HDC hdc, int X, int Y, int width, int height)

обращение в программе

TBitmap* (__stdcall *GetBmpGdi)(HDC hdc, int X, int Y, int width, int height);

неверно? вы уверены?

Изменено пользователем Gingercat
Ссылка на комментарий
  • 0
58 минут назад, Gingercat сказал:

почему это все работает в пределах одной версии?

Потому что по счастливой случайности адресация методов в VMT для TBitmap.exe и TBitmap.dll оказалась идентичной.

 

58 минут назад, Gingercat сказал:

вы уверены?

абсолютно.

 

То, что что-то работает, еще не значит что это работает правильно. И всякие "тонны кода", которые "ну они же работают, значит все я написал правильно" вываливаются с ошибками в самых непредсказуемых местах как раз из-за порчи памяти. И отловить это (и тем более воспроизвести) нереально. Никак.

 

Если вам так удобнее - можете продолжать использовать свой текущий подход, ваше право. Пытайтесь отловить несуществующие ошибки, когда проблема в неправильном API

Изменено пользователем kami
Ссылка на комментарий
  • 0

Спасибо за объяснение - есть повод покопаться дальше и понять. И еще - не нужно утрировать "ну они же работают, значит все я написал правильно"  - я этого не говорил. Если бы был уверен в своей непогрешимости - наверное не стал бы спрашивать. Видимо придется с куском памяти работать, где будет нахолится битмап

Ссылка на комментарий
  • 0
5 минут назад, Gingercat сказал:

не нужно утрировать

Простите, но фраза про тонны кода, как мне показалось, была написана именно в скептически-отрицающем-не-принимающем-аргументы тоне.

 

8 минут назад, Gingercat сказал:

Видимо придется с куском памяти работать, где будет нахолится битмап

Зачем? Вполне достаточно передавать HBITMAP, т.е TBitmap.Handle (если мы говорим про VCL). Сеттер TBitmap.SetHandle сделает всё необходимое.

Ссылка на комментарий
  • 0

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

Просто... нет простого способа создать битмап при работе с DirectX - знаний не хватает.

Ссылка на комментарий
  • 0
20 часов назад, Gingercat сказал:

Если все так печально, почему это все работает в пределах одной версии? И вообще - что значит невозможно? Тонны кода работают на передаче именно классов и экземпляров, а вы завляете что это не верно? Или я чего то не понимаю

Похоже вы действительно чего то не понимаете. Объекты нельзя предавать. Про это написано тонны статей. :) Если хотите передавать именно объекты, тогда вам нужно использовать Package (BPL), вместо обычных dll. Но в этом случае вы будете привязаны к конкретной версии Delphi, а про другие языки можно будет забыть (Ни кто кроме Dlphi не умеет делать BPL).

Обычный способ передачи либо Handle, либо через interface

 

Ссылка на комментарий
  • 0
11 часов назад, DirtyBorov сказал:

либо через interface

Уточнение: интерфейс не должен работать с данными с управляемым временем жизни. К примеру, вы не можете передать между exe и dll IXMLDocument и его составляющие, поскольку этот интерфейс работает с типом string.

Ссылка на комментарий
  • 0
8 часов назад, kami сказал:

Уточнение: интерфейс не должен работать с данными с управляемым временем жизни. К примеру, вы не можете передать между exe и dll IXMLDocument и его составляющие, поскольку этот интерфейс работает с типом string.

Разумеется. Типы данных характерные для Delphi не должны использоваться. Об этом так же написано много. Но лично я не вижу в этом проблем. Гораздо чаще, почему то путают другие вещи: прочитав что объекты передавать нельзя, народ пытается передать указатель! т.е. вместо TObject, делают что то вроде Pointer(Object). Или даже integer(Object). Очень странно. Это ведь то же самое что и передача объекта. Такое чувство что народ совершенно не понимает что такое указатель. 

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...