44

公開されたインターフェイス プロパティを介して相互にリンクする一連のコンポーネントを作成しました。これらはデザイン パッケージに登録され、インストールされます。

公開されたインターフェイス プロパティを使用することは、Delphi ではあまり一般的ではないため、当然のことながら、うまく機能していないように見えます。

コンポーネントが同じフォームに存在する場合は正常に機能しますが、異なるフォーム上のコンポーネント間のインターフェイス プロパティ リンクは問題を引き起こします。

別のフォーム上のコンポーネントへのオブジェクト リンクとは異なり、インターフェイス リンクは IDE によって認識されないようです。IDE で 2 つのフォームを開いていて、それらのコンポーネント間にリンクがある場合、フォーム ビューをテキスト (Alt+F12) として切り替えようとすると、IDE は次のように正しく不平を言います:

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

ただし、プロパティがインターフェイスの場合、これは発生せず、代わりにリンクが切断されます (これは、通知メカニズムを使用して参照をクリアする場合の最良のシナリオです。そうしないと、無効なポインターが残ります)。

同じバグの結果として考えられるもう 1 つの問題は、IDE でプロジェクトを開くときに、フォームが再度開かれる順序が定義されていないため、IDE がコンポーネントへのインターフェイス リンクを持つコンポーネントを含むフォームを開こうとする可能性があることです。別のフォームですが、その別のフォームはまだ再作成されていません。したがって、これは事実上、AV または切断されたリンクのいずれかになります。

Datasets私が使用していた90年代に戻って、Datasourcesフォーム間のリンクが消えるという同様の問題を覚えているので、これはやや似ています.

一時的な回避策として、公開されたプロパティを複製して追加し、インターフェイス プロパティごとに として宣言されている別のプロパティを追加しましたTComponent。これにより、Delphi はフォーム間にリンクがあることを認識できますが、控えめに言っても醜い回避策です。

この問題を解決するために何かできることがあるのだろうか?これは IDE のバグであり、おそらく直接修正することはできませんが、おそらく何かをオーバーライドするか、ストリーミング メカニズムにフックして、このバグをより効果的に回避することができます。

ストリーミング メカニズムについてこれほど深く掘り下げたことはありませんが、Fixup メカニズムがこれに対処することになっているのではないかと思います。があるcsFixups TComponentStateので、回避策が可能であることを願っています。

編集: D2007を使用しています。

アップデート:

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失敗し、何が問題なのかECXEAX私にはわかりません。

4

1 に答える 1

2

要約すると、問題は getter メソッドを持つ公開されたインターフェイス プロパティでのみ発生し、プロパティは別のフォーム/モジュールのコンポーネントを指します (そのフォーム/モジュールはまだ再作成されていません)。このような場合、DFM から復元すると AV が発生します。

バグは の ASM コードにあると確信していますがGetOrdProp、修正する能力を超えているため、最も簡単な回避策は、getter メソッドの代わりに Field を使用し、プロパティで直接読み取ることです。幸いなことに、これは現在の私の場合には十分です。

TComponentまたは、インターフェイスの代わりにプロパティを宣言し、子孫を記述して、必要なインターフェイスをサポートしないコンポーネントをTComponentPropertyオーバーライドすることもできます。ComponentMayBeSetToそしてもちろん、それを使用して登録しますRegisterPropertyEditor

于 2013-05-08T08:44:15.603 に答える