2011-03-09 17 views
0

特定のVCLコントロールが破棄されている間にイベントを発生させ、ハンドラがすでに破棄されているサブクラス化されたフォームで呼び出されるという問題が発生しています(例:コントロールがデストラクタ破壊中のVCLイベント

これは、問題の(第三者)コントロールによる契約違反ですか、私はすべてのイベントハンドラを "if(open)"ガードで捨てるか、これは他のメカニズムによって処理されます。私はおそらく純粋に、__パブリッシュされたクロージャーが自動的に登録解除され、正規の仮想関数がどのように機能するかに似ていると仮定しました。

答えて

1

__published closureはその種の保証をしません。クロージャーは、クラスインスタンスとその内部の関数へのポインタです。しかし、VCLには他の仕組みがあります。

通常、他のコンポーネントに依存するコンポーネントを開発するときは、コンポーネントの削除時に内部参照を確実にクリアすることをお勧めします。 VCLでは、TComponentの無料通知でこれを達成できます。

あなたが依存しているコンポーネントが所有者であり、フォームにない場合は、コンポーネントを登録してこれらの通知を受け取る必要があります。これはFreeNotification関数で行います(通知用コンポーネントを削除するときは、この使用のためにコンポーネントを再度登録解除することを忘れないでください。RemoveFreeNotification)。このコンポーネントと同じフォーム(または所有者)にコントロールが追加されるたびに、追加または削除されたコンポーネントへの参照とともに関数Notificationが呼び出され、アクションが実行されます。

したがって、Notification関数を単に上書きするだけで、親の関数も呼び出すことを忘れないでください。これは、彼らが、もちろんこれを確実にし、彼らはいくつかの理由のためにあなたを忘れてしまった場合は、解放された成分によるdangling pointersがあることを確認する必要がありますサードパーティ製のコントロールである場合

void __fastcall TMyComponent::Notification(TComponent* AComponent, TOperation Operation) 
{ 
    if (Operation == opRemove && AComponent == interestingComponent) 
    { 
     this->interestingComponent = NULL; 
    } 

    inherited::Notification(AComponent, Operation); 
} 

:オーバーロードされた関数は、このようになります。サブクラス化するか、指定したとおりにイベントをリセットすることによって、その機能を追加する必要があります。これが独自のコンポーネントの場合は、必ずこれを行う必要があります。

2

バグのコントロールに「所有者」プロパティが正しく設定されていますか?デフォルトでは、フォームは、TFormインスタンスに対する「所有者」プロパティを持つすべてのコントロールを所有しています。このフォームは、所有しているすべてのコントロールを解放します。 IDEフォームデザイナーを使ってフォームをデザインすると、それがどのように動作するかがその方法です。手動でコントロールを作成する場合は、コンストラクターを使用して「オーナー」プロパティを提供する必要があります。正しいフォームを「所有者」として渡すかどうかを確認します。また、TControlの上に構築されたカスタムコントロールのソースがある場合、そのコンストラクターが基になるTControlコンストラクターに「所有者」プロパティを正しく渡すかどうかを確認してください。

+0

はい、これは、実行時およびクラッシュ中の両方で、設計されたオーナープロパティポイントとフォームの所有者プロパティポイントによって自動的に作成されました。 記録のために、コンポーネントは予想された時刻に破壊されるようです。 〜TWinControlは、明らかにすべての所有コンポーネントを通過して終了します。問題のあるコントロールのデストラクタは、既に破棄されていて、その時点でいくつかの親クラスが残っているフォームにイベントを配信しようとします。 – doynax

+0

デストラクタでイベントを発生させる理由は何ですか?いずれにしても、イベントハンドラを呼び出す前に 'csDestroying'フラグの' ComponentState'プロパティをチェックするだけです。 –

関連する問題