Вопрос пользователя заключается в проблеме создания объекта TButton в DLL для отображения его в основном окне EXE. Пользователь предоставил код, который успешно создает кнопку с помощью команды comps[0](Form1.Handle), но при попытке изменить ее подпись с помощью (FindControl(comps[0](Form1.Handle)) as TButton).Caption:='A'; возникает ошибка "INVALID TYPE CAST". Пользователь также упомянул, что RTTI TPropertyGrid работает корректно, но не может назначить события.
Оригинальный код:
DLL:
library dlltest1;
...
function test(hand:TForm):HWND;
var
a:TButton;
begin
a:=TButton.Create(hand);
a.Show;
result:=a.Handle;
end;
...
EXE:
...
type
TComp=function(Hand:HWND):HWND;
var
comps:array of TComp;
...
procedure TForm1.Button1Click(Sender: TObject);
var
a:HWND;
begin
SetLength(comps,1);
a:=LoadLibrary('dlltest1.dll');
comps[0]:=TComp(GetProcAddress(a,'test'));
(FindControl(comps[0](Form1.Handle)) as TButton).Caption:='A'; // Ошибка INVALID TYPE CAST
end;
Причины ошибки:
Ошибка возникает из-за того, что TButton в DLL и TButton в EXE являются разными типами, так как каждый модуль имеет свою копию типа. Это связано с тем, как компилятор управляет типами в разных модулях. Использование обычной динамической библиотеки (DLL) приводит к тому, что каждая программа имеет полные копии RTL и его состояния, включая менеджер памяти, VMTs, RTTI и локализацию.
Решение проблемы:
Чтобы решить проблему, необходимо использовать пакеты (BPL в Delphi или LPK в Lazarus), которые позволяют разрешать типы во время выполнения и динамически. Это позволяет избежать проблем с идентичностью типов между модулями.
Пример использования RTTI для назначения событий:
procedure TForm1.Button1Click(Sender: TObject);
var
LButton: TButton;
begin
LButton := FindControl(comps[0](Form1.Handle)) as TButton; // Здесь может быть ошибка, если не использовать пакеты
// Используем RTTI для безопасного получения указателя на TButton
LButton := TButton(TObjectPointer(LButton).ClassType.InstanceData);
if Assigned(LButton) then
LButton.OnClick := @HandleButtonClick;
end;
...
procedure HandleButtonClick(Sender: TObject);
begin
// Обработчик события нажатия на кнопку
end;
Обратите внимание, что приведенный выше код является упрощенным примером и может потребовать дополнительной настройки в зависимости от вашей конкретной ситуации и используемой среды разработки.
Альтернативные варианты решения:
Использование RTTI (Runtime Type Information) для работы с объектами, созданными в DLL.
Изменение подхода к проектированию, переход на использование пакетов (BPL/LPK) вместо обычных DLL.
Ознакомление с документацией и примерами использования пакетов в Lazarus и Delphi.
Заключение:
Проблема с использованием TButton через DLL в основном окне EXE связана с идентичностью типов между модулями. Для решения этой проблемы необходимо использовать пакеты, которые позволяют разрешать типы во время выполнения. RTTI может быть использован для работы с объектами, созданными в DLL, но для назначения событий и других операций, требующих прямой работы с типами, необходимо использовать пакеты.
Пользователь столкнулся с проблемой работы с объектом `TButton` через DLL в среде Delphi и Pascal, связанной с несовпадением типов между разными модулями, и ищет решение, включая использование RTTI для назначения событий.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.