Reputation: 41106
I have two COM objects (let's call them Control
and Job
). Control is CoCreatable, Job objects are created by Control.NewJob()
.
Control has a method Control.Start(job)
that makes the specified job the current job. It remains the current job as long as no other job is set.
Now for the client the following behavior appears reasonable for these particular controls:
as long as one of its Jobs exist, Control exists
(trivial: Job holds strong ref to the Control it created)
As long as the client has either a reference to Control or its CurrentJob, neither gets destroyed ("trivial": CurrentJob is a strong ref)
Client should not need to "clear" CurrentJob before releasing references
Now, I have a classic circular reference here, the condition to release it would be both objects not having external references.
I can solve this scenario by mucking around with ATL's InternalRelease implementation, but this is pretty ugly and isolated.
Any suggestions? Existing solutions?
Upvotes: 1
Views: 129
Reputation: 941505
as long as one of its Jobs exist, Control exists
No, fairly sure that this is the rule where you went wrong. Keep your eyes on the ball, the only reason you added the IControl::CreateJob() factory function is to give CJob (the implementation class, not the interface) a CControl* reference. This implies ownership, a particular IJob can only ever be associated with a particular Control instance. CControl should therefore keep a collection of CJobs that it owns.
It now becomes straight-forward:
Upvotes: 2
Reputation: 69662
I don't think ATL has out of the box solution since the behavior in question is sensitive to specific requirements.
As long as the client has either a reference to Control or its CurrentJob, neither gets destroyed ("trivial": CurrentJob is a strong ref)
This requirement assumes that an external strong reference to Control exists from the side of the current Job, since control needs to stay alive with client to job reference only. That is, both control and job have strong references one to another. And then control+job combination needs to correctly handle release of all external references. For instance, this can be achieved the following way.
Job's (and the same way Control's?) CComObjectRootEx::InternalRelease
is overridden and it checks whether the only external reference remained is the control's one. If this is the case, the job is initiating termination check - it calls certain control's method to check its references. If job's reference is the only reference control sees on itself, then both release references one to the other (and terminate).
Upvotes: 1