Перейти к содержанию
  • 0
Ethernet

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

Вопросы

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

 

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

 

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

Создаю 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 эмодзи.

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

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

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


  • Похожий контент

    • От destroyer86
      Всем привет, с помощью Java2Op сделал обертку библиотеки получил модуль с интерфейсами.
      Теперь сам вопрос в JavaInterfaces.pas есть описание:
       
      JUsbManagerClass = interface(JObjectClass) ['{1048A6E9-E1B5-4DA5-A168-ED91E8DE5284}'] {class} function _GetACTION_USB_ACCESSORY_ATTACHED: JString; cdecl; {class} function _GetACTION_USB_ACCESSORY_DETACHED: JString; cdecl; {class} function _GetACTION_USB_DEVICE_ATTACHED: JString; cdecl; {class} function _GetACTION_USB_DEVICE_DETACHED: JString; cdecl; {class} function _GetEXTRA_ACCESSORY: JString; cdecl; {class} function _GetEXTRA_DEVICE: JString; cdecl; {class} function _GetEXTRA_PERMISSION_GRANTED: JString; cdecl; {class} function getAccessoryList: TJavaObjectArray<JUsbAccessory>; cdecl;//Deprecated {class} function openAccessory(accessory: JUsbAccessory): JParcelFileDescriptor; cdecl;//Deprecated {class} function openDevice(device: JUsbDevice): JUsbDeviceConnection; cdecl;//Deprecated {class} procedure requestPermission(device: JUsbDevice; pi: JPendingIntent); cdecl; overload;//Deprecated {class} property ACTION_USB_ACCESSORY_ATTACHED: JString read _GetACTION_USB_ACCESSORY_ATTACHED; {class} property ACTION_USB_ACCESSORY_DETACHED: JString read _GetACTION_USB_ACCESSORY_DETACHED; {class} property ACTION_USB_DEVICE_ATTACHED: JString read _GetACTION_USB_DEVICE_ATTACHED; {class} property ACTION_USB_DEVICE_DETACHED: JString read _GetACTION_USB_DEVICE_DETACHED; {class} property EXTRA_ACCESSORY: JString read _GetEXTRA_ACCESSORY; {class} property EXTRA_DEVICE: JString read _GetEXTRA_DEVICE; {class} property EXTRA_PERMISSION_GRANTED: JString read _GetEXTRA_PERMISSION_GRANTED; end; [JavaSignature('android/hardware/usb/UsbManager')] JUsbManager = interface(JObject) ['{6F603A25-E816-4012-9B23-054B428A4A75}'] function getDeviceList: JHashMap; cdecl;//Deprecated function hasPermission(device: JUsbDevice): Boolean; cdecl; overload;//Deprecated function hasPermission(accessory: JUsbAccessory): Boolean; cdecl; overload;//Deprecated procedure requestPermission(accessory: JUsbAccessory; pi: JPendingIntent); cdecl; overload;//Deprecated end; TJUsbManager = class(TJavaGenericImport<JUsbManagerClass, JUsbManager>) end; Что бы получить доступ к методам интерфейса используется следующая конструкция:
      JavaObject := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.USB_SERVICE); FUsbManager := TJUsbManager.Wrap((JavaObject as ILocalObject).GetObjectID); теперь я могу получить доступ к методам JUsbManager, а как получить доступ к методам JUsbManagerClass
      Вот пример кода на Java, который хочу реализовать в Delphi:
      UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); if (availableDrivers.isEmpty()) { return; } // Open a connection to the first available driver. UsbSerialDriver driver = availableDrivers.get(0); //Вот тут мы видим что из экземпляра класса мы вызываем openDriver, как это сделать в Delphi UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); Как мы можем заметить этого метода в описании интерфейса нет, но есть в классе, как получить доступ к экземпляру класса?
    • От Вадим Смоленский
      Отчего-то, если задать TMediaPlayer.FileName с расширением "mp4", то уже при запуске приложение валится с сообщением "Unsupported media file". Причем в секции initialization юнита FMX.Media.Win присутствует и при запуске отрабатывает такой оператор:
      TMediaCodecManager.RegisterMediaCodecClass('.mp4', SVMP4Files, TMediaType.Video, TWindowsMediaCodec);
      Запускаю под Windows. Файлы *.avi проигрываются без проблем
    • От Вадим Смоленский
      Проблема обозначена в заголовке. Подробнее: при дефолтных установках TFDConnection.ResourceOption  (включенных EscapeExpand, MacroCreate, MacroExpand, ParamCreate, ParamExpand) функция Locate возвращает False. При отключении этих параметров Locate падает с сообщением "Unrecognized token {"
      Вынужден вместо Locate использовать Filter, очень сильно проигрывая в скорости. Хотелось бы все-таки понять, в чем тут дело.
       
    • От BelovAlex
      Приветствую!
      Изменить цвет фона или текста заголовка tstringgrid можно на событии DrawColumnHeader. Но хотелось сделать это с помощью стилей в designtime. Есть ли такая возможность?
      Добавление стилей headeritem приводит в конечном счете к полному обвалу 10.2. При изменении свойств headeritem сначала выскакивает ошибка Intrerface not supported, ну, а потом, любимый access violation в fmx250.bpl. В 10.3 ошибка повторилась
    • От Дмитрий Потапов
      BlurBehind Control. 
       
      Компонент позволяет использовать размытие, по типу, которое реализовано в WIndows 10, т.е компонент позволяет "размыть" то, что находится под ним.
       
      Пусть и увидел это непосредственно в самой студии на стартовой странице (Welcome Page), но все-таки подумал скинуть ссылку сюда.

      Исходники: https://github.com/grijjy/CodeRage2019/tree/master/BlurBehind
      Видео:

       
    • От Павел Блажеев
      Добрый день. Очень нужна Ваша помощь. 
      Мне необходимо сделать координатную сетку в виде точек. При масштабировании панели количество точек должно изменяться . 
      Хочу все это сделать на канве панели. Унаследовал класс и переопределил procedure   Paint; override;
        Tfield = class(TPanel)
            Constructor Create( parent: TFmxObject);
              procedure   Paint; override;
              Procedure   OnMyClick (Sender: TObject);
          end;

      В теле метода я пробовал рисовать. Экспериментировал и столкнулся с такой проблемой. Ничего не отображается. Нет никаких изменений.
      Если я наследую не от Tpanel а от Timage то часть кода работает а часть работает очень криво. Очень хочу разобраться почему .
      {Отображается сразу}
      for a:=1 to 1000 do
            begin
              self.Canvas.Fill.Color:=  TAlphaColors.Crimson;
               self.Canvas.FillEllipse(rect(1,1,10,10),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(round(self.Width-9),round(self.Height-9),round(self.Width), round(self.Height)),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(round(self.Width-9),1,round(self.Width), 9),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(1,round(self.Height-9),10, round(self.Height)),self.AbsoluteOpacity);
            end;
       
      {Отображается только после того как я проскролю Scrollbox на котором лежит панель в крайнее нижнее правое положение}
            self.Canvas.Stroke.Color:=  TAlphaColors.Crimson;
            self.Canvas.Stroke.Thickness:=7;
             Canvas.BeginScene;
            self.Canvas.DrawLine(PointF(20, 20), PointF(100, 50), self.AbsoluteOpacity);
             Canvas.EndScene;
      Подскажите пожалуйста, почему не работает такое с панелью?  Как правильно рисовать на панели? 
      Почему в случае с имейджем все работает так некорректно?  Почему работает только после скрола? 
      Каким способом мне лучше сделать координатную сетку? состоящую из точек как в режиме Design?

       


    • От Вадим Смоленский
      Наверное, детский вопрос задам, и все-таки. Вдруг обнаружил, что в моем проекте никакие блоки try...except не срабатывают. Видимо, дело в каких-то настройках — но в каких именно? Иду в Options => Debugger Options => Embarcadero Debuggers => Native OS Exceptions, пробую там менять установки, толку никакого. Более того — пытаюсь искусственно спровоцировать падение делением на ноль — и вообще никакого падения не происходит, деление на ноль дает ноль! Такая же примерно ерунда с попыткой устроить переполнение.
      Ткните меня в причину носом кто-нибудь, пожалуйста.
      UPD  Через два дня хаотичных экспериментов с настройками всё прочихалось, и exceptions благополучно работают. В чем было дело, так и не понял.
    • От Вадим Смоленский
      У одного из тестировщиков, под Windows, моя сборка регулярно падает с такой ошибкой:
      Cannot create rendering target for 'TCanvas2D2'
      В свое время я и сам с этим сталкивался. У себя поборол уменьшением размеров всех TBitmap ниже некоторого предела. Померили максимальный размер TBitmap на компьютере тестировщика функцией TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize), получилось 8192. На моем компьютере столько же — однако у него падает, а у меня нет. Причем падает не при отрисовке изображения, а уже потом, при каких-то случайных действиях, с отрисовкой не связанных. Всякий раз непредсказуемо. Но он заметил, что если на форму выведено больше крупных изображений, то падает быстрее.
      Как это трактовать и что с этим делать?
    • От Дмитрий Потапов
      Приветствую. Имеется необходимость получить список всех видимых (GUI) компонентов, установленных в Delphi. Я видел где-то, что можно как-то попробовать через ToolsAPI это сделать, но ничего толкового на эту тему так и не нашел. Может есть у кого мысли по этому поводу?
      Если возникнет вопрос: для чего тебе это?
      Ответ: Для приложения LivePreview, которое идет вместе со студией для того, чтобы видеть то, что размещаю на форме непосредственно на устройстве.

      Спасибо!
    • От ComAlex
      Здравствуйте, господа программисты!
      Пытаюсь протестировать Android приложение на любом эмуляторе.
      Всегда одна ошибка "Unable to create process: Performing Streamed Install"
      Понимаю, что ссылок много по данной теме в интернете, но ни одна не помогла.
      Использую Embarsadero Delphi 10.3
      При компиляции на реальный телефон всё работает
      При компиляции на эмулятор даже пустого приложения выдается та же ошибка
      "Unable to create process: Performing Streamed Install"
      В чем проблема? Хотя бы в какую сторону копать?
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

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