[AccessD] Interface Callback Class Questions.

Ken Ismert KIsmert at TexasSystems.com
Thu Jan 29 12:14:43 CST 2004


Robert,

> The report fires, however none of the events (Close) are being hooked.

The only thing I can think of here is that the Report must have a module for
a class to hook its events. Double-check that 'Has Module' is Yes in report
properties. The module can be blank.

> I can run the report once, any attempt to run the report again fails on
> "RemoteReportClose mrRpt.Name" ERROR Number 2467....... Object or
> property... either does not exist or is closed......

I think that if you can hook the Close event, this problem will go away.
CReportHost relies on the Close event to set it's mrRpt reference to
Nothing. If the close event fails, you get a dangling reference - mrRpt is
pointing to an object that has shutdown, and won't respond to further native
property or method requests. It is important to note that the Report object
is still in memory, because it still has one reference, mrRpt, keeping it
alive.

This does suggest adding a failsafe to the CReportHost.CloseRemoteReport
method:

Public Sub CloseRemoteReport()
    On Error GoTo HandleErr
    ' Close Report if Open
    If mrRpt Is Nothing Then Exit Sub
    ' Fires mrRpt_Close
    RemoteReportClose mrRpt.Name
    Exit Sub
HandleErr:
    Select Case Err.Number
    Case 2467   ' Object or Property doesn't exist or is closed
        ' User closed Report, but mrRpt_Close event failed:
        ' Release reference to allow the Report to terminate
        Set mrRpt = Nothing
    Case Else
        Err.Raise Number:=Err.Number, _
            Description:=Err.Description, _
            Source:="CReportHost.CloseRemoteReport" & vbCrLf & Err.Source
    End Select
    Exit Sub
End Sub

> Do I need to hook the opening report to the events in the CReportHost
> class internally of the opening report, such as on the OnOpen event? I'm
> new to the "DEEP" Programming method so I could be way off base.....

One way to look at this is that Events are a 'pull' mechanism. In other
words, declaring an object WithEvents means that you are receiving events
from that object, with no setup on that object's side required. The COM
object framework handles the detials of making sure all subscribers get the
events they signed up for. This is completely transparent to the object
generating the events. What's more, there is no way in VB6 to tell within an
object, say a Report, that other objects are sinking it's events, AFAIK.

(An aside: since Reports and Forms are not 'standard' COM objects, you have
to go through the trouble of hooking their events. This isn't entirely bad,
as it does allow you to selectively enable/disable events at runtime, if you
so need.)

So, the short answer is, for traditional events, you don't hook events in
the object that generates them.

However, if you choose to use interfaces, you can implement a 'push' style
callback mechanism. In this case, lets say an object, O, wants to receive
'events'(or more correctly, callbacks) from another object, P. O would
present itself to P, usually through a subscribe call, like:
    ' Code within O
    rP.Init Me   ' Send reference to myself to P
P, when it wants to call back O, would do something like:
    ' Code within P
    rO.Method    ' Some method defined in an interface
                 ' implemented by O
Of course, O has to unsubscribe when it shuts down:
    ' Code within O
    rP.Term Me   ' P sets rO to nothing, allowing
                 ' O to terminate
Interface callbacks, from O's perspective, look and act very much like
events, except that explicit setup and shutdown are required. From P's
perspective, events and callbacks are very different. Events are internally
defined in P, and raised using RaiseEvent. Callbacks are done using methods
of an externally defined interface, with an object supplied to P at runtime.

Anyway, thanks for your flattering words, and I hope this helps.

-Ken



More information about the AccessD mailing list