Last edit: 05-03-17 Graham Wideman
Visio + Delphi
|Code Structure: Visio Event Handling
Article created: 99-02-02
After Your App has Connected to Visio (using the Visio_Controller.Connect function) then:
1. Call Visio_Controller.EventHandling_Init, providing a callback function.
2. Call Visio_Controller.RegisterForEvent for particular event(s), choosing the Visio object you want to monitor, and the event types you want to see.
3. Later you can call Visio_Controller.UnRegister to stop listening for particular events, or EventHandling_Disconnect to stop listening altogether.
Be sure to read the Visio Automation Reference Help files to get an idea of the functions associated with event handling (such as temporarily disabling an event).
The UML Sequence Diagram below summarizes the interactions between "Your Application", the provided GWVisio_Controller unit, and Visio, with respect to event handling.
A couple of features:
The diagram below illustrates that the most significant part of event handling is providing an IVisioAddOnSink object (interface) to Visio, for Visio to call when an event occurs.
This turns out to be quite straightforward (and is already provided in my demo). The main idea is to create a Type Library resource describing the OLE interface that we want to "expose". In this case it's called GWVisio_AddOn.TLB, and you can view it by dragging it from Explorer to a Delphi edit window (which will bring up the Type Library Editor). This simply declares the names of the interfaces we want to expose, and declares their arguments -- in this case a single function (VisEventProc) and its few arguments.
As a side effect, the Type Library Editor also generates a Pascal equivalent, so that we now have a unit declaring the OLE interface, which is then used in GWVisio_Controller in the declaration of the actual class (TVisioAddOnSink) that implements the interface.
I should warn at this stage that if you read the Delphi docs (or third-party books) on Type Libraries, you might easily be led down a lengthy path, since this Visio's AddAdvise event apparatus is a little unorthodox, and our use of a Type Library likewise. In particular, for this application we do not have to register the type library with the operating system (in the Registry etc), since Visio won't be spontaneously "looking for" our IVisioAddOnSink, we hand it to Visio. Hence a number of finicky steps are avoided.
One last mysterious aspect -- you will see that the GWVisio_Controller unit initialization calls TAutoObjectFactory.Create. This is to set up the OLE library apparatus that (using the Type Library) later marshals the parameters for VisEventProc when Visio sends an event notification. To be honest, I'm not sure this is the most economical way to achieve the desired effect, but it does the trick.
This is far from the last word on handling Visio events. Amongst the remaining "exercises for enthusiasts":
Note that there shouldn't be a problem if the callback avoids the VCL. Also, if Your App is written as a VSL (ie: Visio DLL) that should again avoid a problem as (I believe) VSLs are modal with respect to Visio (so only one can be active at a time). For better or worse, with a stand-alone "Your App" the threading problem may be rare to show up anyway, since to occur you would need to be actively using Your App while Visio was simultaneously grinding away generating events. Of course, that could more easily happen if Your App is manipulating Visio, causing Visio to generate events that Your App is listening for...
Possible solutions to threading problem: If your callback has a risk of a threading problem, then there are a number of solutions, discussed in various third party books, including Delphi 4 Developer's Guide. One strategy involves having the callback function queue the event info, which then awaits the main thread code checking the queue. Or the callback can send a Windows message to the main thread code to alert it that event info is awaiting attention.
Go to: Up to: [Visio] [GWVisio Demo for Delphi]