Опубликованные ошибки в интерфейсе и обходные пути

40

Я написал набор компонентов, которые связывают друг с другом через опубликованные свойства интерфейса. Они регистрируются и устанавливаются в пакет дизайна.

Использование опубликованных свойств интерфейса не так распространено в Delphi и, следовательно, неудивительно, похоже, не работает так хорошо.

Он отлично работает, когда компоненты находятся в одной и той же форме, однако свойства интерфейса между компонентами разных форм вызывают проблемы.

В отличие от ссылок объектов на компоненты в другой форме, интерфейсные ссылки, похоже, не распознаются IDE. То, что я имею в виду, лучше всего описывается примером, когда у вас есть 2 формы, открытые в IDE, и у них есть ссылки между компонентами на них, а затем попытка переключиться на представление формы в виде текста (Alt + F12) приведет к тому, что IDE будет правильно жаловаться, что:

Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.

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

Другая проблема, вероятно, в результате такой же ошибки заключается в том, что при открытии проекта в среде IDE порядок, в котором формы будут открываться повторно, составляет undefined, поэтому среда IDE может попытаться открыть форму, содержащую компоненты, которые имеют интерфейс ссылки на компоненты в другой форме, но эта другая форма еще не воссоздана. Таким образом, это эффективно приводит либо к AV, либо к разрыву ссылок.

В 90-е годы, когда я использовал Datasets и Datasources, я помню похожие проблемы со связями между исчезающими формами, поэтому это несколько похоже.

В качестве временного обходного пути я добавил повторяющиеся опубликованные свойства, для каждого свойства интерфейса я добавил другое, объявленное как TComponent. Это заставляет Delphi знать, что существует связь между формами, но, по меньшей мере, это уродливое обходное решение.

Так что я задаюсь вопросом, есть ли что-то, что я могу сделать, чтобы исправить эту проблему? Это ошибка IDE и, вероятно, не исправляется напрямую, но, возможно, я могу переопределить что-то или иначе подключиться к механизму потоковой передачи, чтобы более эффективно обходить эту ошибку.

Я никогда не заходил так глубоко в механизм потоковой передачи, но я подозреваю, что механизм Fixup должен иметь дело с этим. Существует csFixups TComponentState, поэтому я надеюсь, что возможно обходное решение.

Изменить: использование D2007.

Update:

Новый обновленный воспроизводимый пример, загруженный в http://www.filedropper.com/fixupbugproject2

Добавлен property ComponentReference: TComponent, чтобы было легко сравнивать и трассировать интерфейс с потоковой передачей компонентов.

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

В процедуре GlobalFixupReferences в модуле classes он вызывает:

(GetOrdProp(FInstance, FPropInfo) <> 0)

который в конечном итоге выполняется:

function TInterfacedComponent.GetInterfaceReference: IInterface;
begin
// uncomment the code bellow to avoid exception
{  if (csLoading in ComponentState) and (FInterfaceReference = nil) then
  // leave result unassigned to avoid exception
  else
}
    result := FInterfaceReference; // <----- Exception happens here
end;

Как вы можете видеть из комментария, единственный способ избежать исключения - оставить результат неназначенным, но это нарушает функциональность, так как сравнение выше в GlobalFixupReferences не выполняется из-за GetOrdProp <> 0, что приводит к обрыву ссылки.

более глубокое отслеживание более точного местоположения исключения находится в

procedure _IntfCopy(var Dest: IInterface; const Source: IInterface); в system единица

Эта строка, в частности, вызывает read of address 0x80000000

{   Now we're into the less common cases.  }
@@NilSource:
        MOV     ECX, [EAX]      // get current value

Итак, почему MOV терпит неудачу, и что не так с ECX или EAX Я понятия не имею.

  • 5
    Это интересный вопрос. Это немного выходит за рамки моего личного опыта. Я подозреваю, что если бы у вас был демонстрационный проект, который помог бы любым начинающим следователям.
  • 1
    @DavidHeffernan Это довольно легко воспроизвести, все, что вам нужно, это потомок TComponent с опубликованным свойством типа IInterface. Зарегистрируйте его, установите пакет и поместите по одному на каждую из двух пустых форм. Сказав это, я мог бы сделать это сам и позволить вам, ребята, поиграть с этим ...
Показать ещё 7 комментариев
Теги:
interface
ide
delphi-2007
design-time

1 ответ

1

Подводя итог, проблема возникает только с опубликованными свойствами интерфейса, которые имеют метод getter, а свойство указывает на компонент на другой форме/модуле (и эта форма/модуль еще не воссоздана). В этом случае восстанавливающая форма DFM вызывает AV.

Я уверен, что ошибка находится в коде ASM в GetOrdProp, но это выходит за рамки моей способности исправлять, поэтому проще всего использовать поле вместо метода геттера и прочитать его непосредственно в свойстве. Это, к счастью, достаточно хорошо для моего дела в настоящее время.

В качестве альтернативы вы можете объявить свойство как TComponent вместо интерфейса, а затем написать потомок TComponentProperty, переопределить ComponentMayBeSetTo, чтобы фильтровать компонент, который не поддерживает требуемый интерфейс. И, конечно, зарегистрируйте его, используя RegisterPropertyEditor

  • 0
    Для этого есть запись QC?
  • 1
    нет, я не верю в КК, основываясь на предыдущем опыте ...
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню