Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Component that references another component


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 4 - Last Post: Sep 8, 2014 7:20 AM Last Post By: John Farmer
John Farmer

Posts: 22
Registered: 11/12/10
Component that references another component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 27, 2014 1:04 PM
Hi,

I have implemented two components, TCOMPort and TCOMIndicator. TCOMPort has a property named CTSIndicator written as follows.

__property TCOMIndicator *CTSIndicator = {read = FCTSIndicator, write = FCTSIndicator, default = NULL};

For a TCOMPort component, the CTSIndicator property appears in the object inspector as expected and I am able to select any TCOMPortIndicator objects as expected.

If, after selecting TCOMIndicator component, I then delete the TCOMIndicator component from the form I get an access violation, which is not totlly unexpected since the property that was assigned to the indicator can no longer reference it.

What is the procedure to handle cases where one component references another, on a form, but one of the components then gets deleted at design-time? I am assuming that somehow the original property value needs to be set to NULL after the compopnent that it referenced is deleted but cannot see how this is done.

I am using BCB6 patched to V3.

Regards
FarmerJo
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Component that references another component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 27, 2014 2:08 PM   in response to: John Farmer in response to: John Farmer
{quote:title=John Farmer wrote:}
__property TCOMIndicator *CTSIndicator = {read = FCTSIndicator, write = FCTSIndicator, default = NULL};

You don't need to specify a default for such a property. It has an implicit default of 0.

{quote:title=John Farmer wrote:}
What is the procedure to handle cases where one component references another, on a form, but one of the components then gets deleted at design-time? I am assuming that somehow the original property value needs to be set to NULL after the compopnent that it referenced is deleted but cannot see how this is done.

You need to implement the Notification() method to detect when the TCOMIndicator object is freed before the TCOMPort is freed, eg:

class TCOMPort : public TComponent
{
    typedef TComponent inherited;
private:
    TCOMIndicator *FCTSIndicator;
    void __fastcall SetCTSIndicator(TCOMIndicator *Value);
    //...
protected:
    virtual void __fastcall Notification(TComponent *AComponent, TOperation Operation);
    //...
__published:
    __property TCOMIndicator* CTSIndicator = {read = FCTSIndicator, write = SetCTSIndicator};
};
 
void __fastcall TCOMPort::Notification(TComponent *AComponent, TOperation Operation)
{
    inherited::Notification(AComponent, Operation);    
    if ((Operation == opRemove) && (AComponent == FCTSIndicator))
        FCTSIndicator = NULL;
}
 
void __fastcall TCOMPort::SetCTSIndicator(TCOMIndicator *Value)
{
    if (Value != FCTSIndicator)
    {
        if (FCTSIndicator)
            FCTSIndicator->RemoveFreeNotification(this);
        FCTSIndicator = Value;
        if (FCTSIndicator)
            FCTSIndicator->FreeNotification(this);
    }
}


--
Remy Lebeau (TeamB)
John Farmer

Posts: 22
Registered: 11/12/10
Re: Component that references another component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 6, 2014 5:34 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hi Remy,

Many thanks for the quick and helpful reply, as usual greatfully received. I have one or two related questions.

Why is this syntax used.

typedef TComponent inherited;
inherited::Notification .....

Instaed of.

TComponent::Notification .....

I have seen this syntax in other code and wondered why it is used?

Also, in your reply you defined a SetCTSIndicator as follows.

if (FCTSIndicator)
FCTSIndicator->RemoveFreeNotification(this);
FCTSIndicator = Value;
if (FCTSIndicator)
FCTSIndicator->FreeNotification(this);

Whereas my code simply defines the CTSIndicator property as follows.

__property TCOMIndicator *CTSIndicator = {read = FCTSIndicator, write = FCTSIndicator};

I would be interested in knowing why the RemoveFreeNotification and FreeNotification are used.

Regards
FarmerJo
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Component that references another component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 6, 2014 11:13 AM   in response to: John Farmer in response to: John Farmer
John wrote:

Why is this syntax used.

typedef TComponent inherited;
inherited::Notification .....
Instaed of.

TComponent::Notification .....

It mimics what Delphi component do in C++. If you look at any of the native
VCL .hpp files, you will see that all components have an 'inherited' typedef.
It helps make code more self-documenting when you can see 'inherited::Notification(...)'
instead of 'TComponent::Notification(...)'. It also helps protect your code
if you ever change the parent class that you derive from. All you have to
do it change the typedef accordingly, instead of having to hunt through your
component's code changing all of the references to the old parent class.

Also, in your reply you defined a SetCTSIndicator as follows.
<snip>
Whereas my code simply defines the CTSIndicator property as follows.
<snip>
I would be interested in knowing why the RemoveFreeNotification and
FreeNotification are used.

That is the key to making safe references to external components. You must
explicitly register to receive a notification when the referenced component
is freed before your own component is freed, so that you can set your reference
to NULL. FreeNotification() enables that notification, and RemoveFreeNotification()
disables it. Your code was not do that registration, which is why your code
was crashing when trying to access a component that had already been freed.
you were not being told the component was freed, so your reference was not
reset to NULL.

--
Remy Lebeau (TeamB)
John Farmer

Posts: 22
Registered: 11/12/10
Re: Component that references another component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 8, 2014 7:20 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hi Remy,

Many thanks once again for all your help.

Regards
FarmerJo

Remy Lebeau (TeamB) wrote:
John wrote:

Why is this syntax used.

typedef TComponent inherited;
inherited::Notification .....
Instaed of.

TComponent::Notification .....

It mimics what Delphi component do in C++. If you look at any of the native
VCL .hpp files, you will see that all components have an 'inherited' typedef.
It helps make code more self-documenting when you can see 'inherited::Notification(...)'
instead of 'TComponent::Notification(...)'. It also helps protect your code
if you ever change the parent class that you derive from. All you have to
do it change the typedef accordingly, instead of having to hunt through your
component's code changing all of the references to the old parent class.

Also, in your reply you defined a SetCTSIndicator as follows.
<snip>
Whereas my code simply defines the CTSIndicator property as follows.
<snip>
I would be interested in knowing why the RemoveFreeNotification and
FreeNotification are used.

That is the key to making safe references to external components. You must
explicitly register to receive a notification when the referenced component
is freed before your own component is freed, so that you can set your reference
to NULL. FreeNotification() enables that notification, and RemoveFreeNotification()
disables it. Your code was not do that registration, which is why your code
was crashing when trying to access a component that had already been freed.
you were not being told the component was freed, so your reference was not
reset to NULL.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02