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

Зависание приложения при выгрузке dll библиотеки с формой FireMonkey

Вопросы

Здравствуйте. Возникла следующая проблема. Создал dll библиотеку с формой FireMonkey. Из приложения на VCL подключаю библиотеку, вызываю функцию создания формы

procedure CreateHD;
begin
  FormHD := TFormHD.Create(nil);
  FormHD.Caption := 'HD';
  FormHD.Show;
end;

форма создаётся, далее вызываю функцию закрытия и уничтожения формы FM

procedure CloseHD;
begin
  FormHD.Close;
  FreeAndNil(FormHD);
end;

Но при попытке выгрузить dll приложение зависает.

 

Возможно уничтожение формы FM как-то отличается от VCL и нужно что-то вызвать ещё кроме FreeAndNil или проблема в другом?

 

(dll и приложение написаны в Delphi XE6)

Приложение.zip

Поделиться сообщением


Ссылка на сообщение

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

  • 0

А при пошаговой отладке на какой строке кода происходит зависание?

На строке выгрузки библиотеки.

FreeLibrary(HLib);

Поделиться сообщением


Ссылка на сообщение
  • 0

Как я понимаю, если в dll будет VCL форма, то все хорошо? Надо посудить, что если библиотека создавалась на основе библиотеки FMX, то и работать с ней надо средствами FMX, то есть загружать и выгружать средствами FMX. Но вероятно я не прав. Я бы поэкспериментировал, а именно попробовал бы поработать с dll из проекта на FMX.

Поделиться сообщением


Ссылка на сообщение
  • 0

Как я понимаю, если в dll будет VCL форма, то все хорошо? Надо посудить, что если библиотека создавалась на основе библиотеки FMX, то и работать с ней надо средствами FMX, то есть загружать и выгружать средствами FMX. Но вероятно я не прав. Я бы поэкспериментировал, а именно попробовал бы поработать с dll из проекта на FMX.

Да, если в dll будет VCL форма, то она выгружается без проблем. Библиотека не создаётся на основе FMX или VCL, библиотека это отдельный от них проект. К тому же выгрузка производится функцией WinAPI, она не знает о FMX и о VCL.

Поделиться сообщением


Ссылка на сообщение
  • 0

Столкнулся с похожей проблемой. Зависать FreeLibrary может если в dll в секции финализации какого-то модуля есть что-то что не положено делать в DLLMain, а делать там не положено очень много чего. Очевидное решение вызвать всю финализацию до выгрузки библиотеки. Это можно сделать если собрать dll как bpl пакет, это будет такая же dll, но у нее будут экспортироваться функции Initialize и finalize, об этом как раз есть в цикле статей из предыдущего совета. Мне помогло, но не понравилось что в bpl суется много всего и размер библиотеки сильно вырастает. Если bpl не подходит вот еще несколько костылей 

1) Загрузить dll из памяти, не средствами винды а самостоятельно, примеров в интернете куча, в этом случае DllMain вызывается не загрузчиком винды (со своими локами системных структур и дедлоками), а нашим кодом который ничего не блокирует, соответственно все проходит гладко. У меня такой способ заработал. Не на всех dll такое заработает, зависит от полности эмуляции загрузчика винды, на обычной форме сработал самый простой вариант c адаптацией под Delphi 2010. 

2) На стэковерфлоу у человека похожая проблема и ему помогла загрузка и выгрузка dll из секции инициализации/финализации хоста (не проверял, может и перевел не верно что он там пишет)

3) Я попробовал эмулировать вызов FinalizeUnits, тоже сработало, правда используются хаки:

{
  Модуль позволяет решить проблему с зависанием при выгрузки dll с FMX формой.
  Модуль нужно подключить самым первым в dpr файле, до подключения любых файлов
  с FMX, и вызвать функцию FinalizeAllExceptSystemUnits непосредственно перед
  выгрузкой dll через FreeLibrary.

  Например ваша dll экспортирует функцию уничтожения формы, которую вызывает
  хост перед выгрузкой, например

  procedure Done; stdcall;
  begin
    try
      //Уничтожим форму
      FreeAndNil(Form1);

      //Произведем финализацию модулей которая должна быть выполнена
      //в FreeLibrary, но все зависает
      FinalizeAllExceptSystemUnits;

      //Освобождаем GDI именно после финализации FMX
      if Assigned(GenericSansSerifFontFamily) then
        GenericSansSerifFontFamily.Free;
      if Assigned(GenericSerifFontFamily) then
        GenericSerifFontFamily.Free;
      if Assigned(GenericMonospaceFontFamily) then
        GenericMonospaceFontFamily.Free;
      if Assigned(GenericTypographicStringFormatBuffer) then
        GenericTypographicStringFormatBuffer.free;
      if Assigned(GenericDefaultStringFormatBuffer) then
        GenericDefaultStringFormatBuffer.Free;
      GdiplusShutdown(gdiplusToken);
    except
      on E: Exception do
        OutputDebugString(PChar(E.Message));
    end;
  end;
  
  author: Виктор Федоренков
  email: victor.fedorenkov@gmail.com
  skype: victor_fedorenkov
}
unit suEmulFinalizeUnitsForUnloadDllUnit;

interface

uses
  Windows,
  SysUtils;

procedure FinalizeAllExceptSystemUnits;

implementation

var
  _IsFinalizedThisUnit: Boolean = False;

//Получение структуры PackageInfo нашего приложения
//В System она находится в переменной InitTable, но не видна из других модулей
function GetInitTable: PackageInfo;
var
  Lib: PLibModule;
  Offset: LongWord;
  TypeInfo: PPackageTypeInfo;
begin
  Result := nil;

  Lib := LibModuleList;

  if not Assigned(Lib) then
    Exit;

  //Если загружено несколько модулей (BPL пакетов), то выходим,
  //я не изучал как работает механизм загрузки/выгрузки BPL, поэтому на всякий
  //случай выходим
  if Assigned(Lib^.Next) then
    Exit;

  Typeinfo := Lib^.TypeInfo;
  if Assigned(TypeInfo) then
  begin
    //Мы имеем TPackageTypeInfo
    //Теперь по нему можно получить PackageInfo
    //Воспользуемся особенностями компилятора.
    //В IDA видно, что ссылка TypeInfo указывает на середину структуры
    //PackageInfo программы
    //Поэтому для того что бы вычислить PackageInfo нужно вычесть из адреса
    //TypeInfo смещение этого поля
    Offset := LongWord(@PackageInfoTable(nil^).TypeInfo);
    Result := PackageInfo(PByte(TypeInfo) - Offset);
  end;
end;

//Проведем финализацию всего кроме RTL
procedure FinalizeAllExceptSystemUnits;
var
  P: Pointer;
  Count: Integer;
  OldProtect: LongWord;
  LExitProc: procedure;
  InitTable: PackageInfo;
  Table: PUnitEntryTable;
begin
  while ExitProc <> nil do
  begin
    @LExitProc := ExitProc;
    ExitProc := nil;
    LExitProc;
  end;

  InitTable := GetInitTable;

  if not Assigned(InitTable) then
    Exit;

  Table := InitTable^.UnitInfo;

  if not Assigned(Table) then
    Exit;

  //Мы не можем получить доступ к количеству инициализированных модулей, поэтому
  //будем работать из расчета что были инициализированы все модули.
  //Ведь так и есть, инициализирована только часть модулей может быть если
  //при нициализации произошло исключние в одном из модулей, но тогда будет
  //запущена финализация всего и видимо библиотека не будет загружена
  Count := InitTable^.UnitCount;

  //Разрешаем изменять структуру в которой хранятся ссылки на инициализаю/финализацию всех юнитов
  //для того что бы затирать уже вызваные секции финализации
  if not VirtualProtect(Table, SizeOf(PackageUnitEntry) * Count,
        PAGE_READWRITE, OldProtect) then
    Exit;

  try
    //Вызываем секции финализации пока не будет вызвана секция этого модуля
    //Так как этот модуль указан первым в dpr файле, то перед ним останется
    //только системные модули (менеджер памяти, sysutils) которые и без того
    //нормально финализируются в dll, и их работа нужна что бы отработать
    //выгрузку dll
    while not _IsFinalizedThisUnit do
    begin
      Dec(Count);

      //Получим указатель на секцию финализации модуля
      P := Table^[Count].FInit;

      //Удалим из структуры указатель на эту функцию что бы родной механизм
      //финализации повторно не начал ее выгружать
      Table^[Count].FInit := nil;

      if Assigned(P) and Assigned(Pointer(P^)) then
      asm
        //Похоже какой-то баг компилятора в 10.1 Berlin, и вызов финализации
        //через TProc(P)(; как это сделано в оригинальной System.FinalizeUnits падает,
        //поэтому вызываем ассемблером
        call [p];
      end;
    end;
  except
    FinalizeAllExceptSystemUnits;  //Пробуем финализировать другие модули
    raise;
  end;
end;

initialization

finalization
  //Выставим флаг что прошла финализация модуля
  _IsFinalizedThisUnit := True;
end.

Интересно услышать комментарий спецов по последнему способу, может я что-то не учел

Отредактировал vic85

Поделиться сообщением


Ссылка на сообщение
  • 0

Есть вот такой вот комментарий принципиально поводу создания FMX внутри библиотеки http://forum.vingrad.ru/index.php?showtopic=380246&view=findpost&p=2626848

Поделиться сообщением


Ссылка на сообщение
  • 0

Я собрал пример из стартпоста на 10.1 Berlin - при выгрузке dll приложение падает, если собрать либу как bpl или добавить в CloseHD вызов FinalizeAllExceptSystemUnits из предыдущего моего коммента то выгружается все нормально. Значит дело было в локах из DllMain, но остается совершенно другая проблема.

При закрытии самого хоста в деструкторе application все падает. Дело в том что при уничтожении формы ищется новое активное окно, в нормальном приложении оно не находится и все закрывается, а после выгрузки загруженной dll c fmx такое окно находится - это ApplicationHWND из dll, оно создается при создании формы но не уничтожается. После выгрузки dll окно остается висеть, и его оконная процедура указывает на уже выгруженную область, и когда VCL находит этот хэндл и пытается сделать его активным - винда посылает этому окно сообщение и для его обработки вызывает WndProc окна которого уже нет. Все помирает.

FMX при создании окна Application позволяет получить хэндл окна снаружи с помощью RegisterApplicationHWNDProc, похоже именно так делает сама delphi что бы в себе отображать fmx формы в самой среде в десигнтайме. Что бы повторить этот трюк нужно экспортировать из dll еще одну функцию:

procedure InitApplication(VclApplicationHandleProc, VclApplicationStateProc: Pointer);
begin
  FMX.Platform.Win.RegisterApplicationHWNDProc(VclApplicationHandleProc);
  if FMX.Forms.Application <> nil then
    FMX.Forms.Application.ApplicationStateQuery := VclApplicationStateProc;
end;

Ну а в самом хосте вызвать эту функцию:

TInitVCLApplicationFunc = procedure(VclApplicationHandleProc, VclApplicationStateProc: Pointer);

var
  InitApplication: TInitVCLApplicationFunc;

function VclApplicationHandle: HWND;
begin
  Result := Vcl.Forms.Application.Handle;
end;

type
  TFMXApplicationState = (None, Running, Terminating, Terminated);

function VclApplicationState: TFMXApplicationState;
begin
  if Vcl.Forms.Application <> nil then
    Result := TFMXApplicationState.Running
  else
    Result := TFMXApplicationState.None;
end;

...

procedure TForm1.Button3Click(Sender: TObject);
begin
  HLib:=0;
  try
    HLib := LoadLibrary('Project1.dll');
    if HLib > HINSTANCE_ERROR then
      begin
        InitApplication := GetProcAddress(HLib,'InitApplication');
        CreateHD := GetProcAddress(HLib,'CreateHD');
        CloseHD := GetProcAddress(HLib,'CloseHD');      
      end else ShowMessage('Библиотека не найдена');

      InitApplication(@VclApplicationHandle, @VclApplicationState);
  except
    if HLib > HINSTANCE_ERROR then FreeLibrary(HLib);
  end;
end;

Все это набросано на коленке, и тестировалось на пустой форме, возможно есть еще какие-то ньюансы которые должны знать разработчики FMX.

Отредактировал vic85

Поделиться сообщением


Ссылка на сообщение

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

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

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

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

  Разрешено использовать не более 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()); Как мы можем заметить этого метода в описании интерфейса нет, но есть в классе, как получить доступ к экземпляру класса?
    • От 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?

       


    • От Дмитрий Потапов
      Приветствую. Имеется необходимость получить список всех видимых (GUI) компонентов, установленных в Delphi. Я видел где-то, что можно как-то попробовать через ToolsAPI это сделать, но ничего толкового на эту тему так и не нашел. Может есть у кого мысли по этому поводу?
      Если возникнет вопрос: для чего тебе это?
      Ответ: Для приложения LivePreview, которое идет вместе со студией для того, чтобы видеть то, что размещаю на форме непосредственно на устройстве.

      Спасибо!
    • От ComAlex
      Здравствуйте, господа программисты!
      Пытаюсь протестировать Android приложение на любом эмуляторе.
      Всегда одна ошибка "Unable to create process: Performing Streamed Install"
      Понимаю, что ссылок много по данной теме в интернете, но ни одна не помогла.
      Использую Embarsadero Delphi 10.3
      При компиляции на реальный телефон всё работает
      При компиляции на эмулятор даже пустого приложения выдается та же ошибка
      "Unable to create process: Performing Streamed Install"
      В чем проблема? Хотя бы в какую сторону копать?
    • От Дмитрий Потапов
      Задался идеей написания IPTV приложения "для себя", в котором при желании смог бы реализовать что-то необходимое и удалить то, что не нужно.
      Собственно вопрос в другом: Я написал простое приложение, которое отлавливает коды кнопок с пульта, приложение по сути самое банальное, использует OnKeyDown и OnKeyUp (чисто для теста). И по нажатию на кнопку на пульте высылает например в Memo или ListBox Информацию о нажатой кнопке (включая ее код).
      Но суть в том, что далеко не все кнопки таким образом распознаются. Для примера:
      Кнопки громкости, назад, домой, увеличение\уменьшение громкости, стрелки(влево, вправо, вверх, вниз) и центральная кнопка (по совместительству OK).
      Цифры все определяются, как одна - 0
      Кнопки, которые не определяются (не срабатывает событие, ибо если был бы неизвестен код, то думаю, в таком случае получил бы все, кроме кода кнопки), но по нажатию кнопки, которая не определяется приложением - ничего не происходит вообще.
       
      Вопрос: Есть ли возможность как-то "научить" приложение распознавать эти кнопки? (Я где-то читал, может даже и здесь, что это все так реализовано именно на уровне самого FireMonkey, будто этих кнопок вообще не существует).
      Если эта тема уже поднималась на форуме или вопрос очень просто решается - извиняюсь)
      Решение: http://fire-monkey.ru/topic/5624-как-отловить-кнопки-пульта-ду/?do=findComment&comment=36399
       
    • От neo
      Ребята здарова!
      выручайте) весь уже измучился =( не получается =(
      Тема такая, работаю с хуком, использую WH_KEYBOARD_LL
      тк нужно работать и с 32 битной и 64 битной разрядностью.
      и вообще мне нравится с ним работать всё очень просто и удобно но появилось одно НО =(
      WH_KEYBOARD_LL работает до добавления сообщения в очередь в контексте потока.
      и это действительно так =(
      дело в том что я через хук ловлю введённую информацию и потом обрабатываю это через
      idHTTP (ищу в интернете ответ)... если сигнал хороший то всё круть... а когда связь не очень..
      и происходят небольшие задержки..
      как я понимаю в WH_KEYBOARD_LL складируются результаты которые он не может передать
      и затем хук выбивается... тоесть чтобы всё вновь заработало нужно сделать так
       
      KeyboardHandle:=SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardHook, HInstance, 0);
      и хук по прежнему работает до тех пор пока не вылетит вновь.
      Чтобы решить эту проблему как я понял нужно использовать PeekMessage или GetMessage
      и удалять излишки... Но в сети очень мало информации о том как ими пользоваться я не понимаю
      куда и как их вставлять.
      Я делал вот так... писал в ДЛЛке
      function KeyboardHook(code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
      var
      msg:TMsg;
      begin
       if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then exit;
       if code>=0 then
        begin
          if (wParam=WM_KEYDOWN) then
          begin
          SendMessage(FindWindow('TForm1', 'Form1'), KeyboardEvent, 0,PBDLLHOOKSTRUCT(lParam).vkCode);
          end;
        end;
        Result:=CallNextHookEx(KeyboardHandle, code, wParam, lParam)
      end;
      // if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then exit;
      // типа если есть излишки выходи

      так же вставлял там это:
          while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
          begin
              TranslateMessage(Msg);
              DispatchMessage(Msg);
            end;
      но не помогает =(
      Может это где-то в ЕХЕшнике нужно вставлять? я не понимаю как с ним работать =(
      Может кто на форуме знает? помогите пожалуйста ответом
    • От PavelS
      Здравствуйте! Начал изучать FireMonkey  и столкнулся с тем, что TBitmap не поддерживает размер изображения больше 8132, кажется. Т.е. большие размеры рисунка он грузит, но за счёт потери качества, размер пиксела растёт, а размер рисунка по оси всё равно не превышает 8132. В то же время в простом дельфи можно грузить и работать с гораздо большими размерами, например, один из файлов имеет размер 61216 х 1486 точек. Подскажите пожалуйста, есть ли возможность работать с большими файлами в FireMоnkey и как это можно организовать? Программа создаётся для работы только в Windows.
    • От SIARHEI RAHOUSKI
      Создал проект там куча компонентов. Но разворачивании формы на весь экран компоненты размер не меняют:
      Прочитал про свойства align Но как только я выставлю Group box например left другим right все сбивается в кучу и поправить это не могу. 
      Как настроить align ?

  • Последние посетители   0 пользователей онлайн

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

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