2013-04-26 3 views
42

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

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

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

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

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

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

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

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

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

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

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

Редактировать: Использование 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. Зарегистрируйте его, установите пакет и поместите его на каждую из двух бланков. Сказав это, я мог бы сделать это сам и позволить вам, ребята, поиграть с ним ... –

+1

Я думаю, что это поможет, если вы это сделаете. Опустите барьеры для нас. –

ответ

1

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

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

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

+0

Есть ли запись для контроля качества? –

+0

нет, я не верю в QC, основываясь на предыдущем опыте ... –

+1

Это только увековечивает проблему. Вы не можете жаловаться, что это не исправлено, если они не знают об этом. Вы можете жаловаться, если они это сделают :) (Не то, чтобы я обвиняю вас в жалобах, но вы понимаете, что я имею в виду.) –

Смежные вопросы