123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- <html>
- <head>
- <title>Jacob can register Java classes for MS application events or callbacks</title>
- <BODY>
- <H2>Overview</H2>
- Jacob can register Java classes for MS application events or callbacks.
- <H2>Sequence of Events</H2>
- The normal flow for this is:
- <OL>
- <LI>Application thread creates an instance of the event handler and registers it with Jacob</li>
- <LI>The application continues on doing other work.</li>
- <LI>Some time later, the MS application takes some action and initiates the event callback.</li>
- <LI>The Java VM receives the event and spins up a new thread to handle it.</li>
- <LI>The Jacob jni EventProxy in the dll is called by the VM.</li>
- <LI>The Jacob jni EventProxy creates Variant objects to handle the parameters of the passed in event.</li>
- <LI>The Jacob jni EventProxy sends the name of the callback and the array of Variant objects to the Java InvocationProxy
- that was registered to catch events.</li>
- <LI>The Java InvocationProxy uses reflection to map the event name to a method name with the exact same name.</li>
- <LI>The Java InvocationProxy sends the message to the registered event handler and returns if the event handler
- is of type void (standard behavior). </li>
- <LI>The Java InvocationProxy sends the message to the registered event handler and returns the Variant that
- resulted from the call back to the Jacob jni EventProxy that then returns it to the windows calling
- program.
- </li>
- </OL>
- <H2>SWING Issues</H2>
- Swing developers should note that this message comes in on a thread other than the event thread. All objects receiving events
- that require user intervention or drawing in the UI should use invokeLater() to post requests for actions onto
- the event queue. Failure to do so will insure random failures in the GUI. Java Web Start (JWS) and other launchers
- can have additional issues related to the class loader. The Jacob C++ library uses FindClass() to find the Variant
- class when building the parameter list. FindClass() uses the system class loader which includes only the classes
- specified at run time or in the CLASSPATH. Most of the application classes in this situation live in an alternate
- set of class loaders that were created when the launcher located and ran the application classes. This means
- that the search for Variant will fail usually with the silent and immediate termination of the Java application.
- The thread classloader probably can�t be used to try and find the class because this new thread does not have
- a classloader associated with it other than the system class loader. The end result is that the Variant class
- needs to be located via other means and that the thread classloader should be set to be the context class loader
- of the event handler class.
- <H2>1.8 and 1.9 behavior</H2>
- The Jacob EventProxy class has been modified (off of the 1.8 tree) so that it takes a two step approach towards fixing these
- problems.
- <OL>
- <LI>The EventProxy constructor now accepts an extra object, an instance of the Variant class. This gives the
- EventProxy a way to get to the Variant class and thus to its classloader. All of the callers of the
- constructor have been modified to pass a Variant object to the EventProxy without programmer intervention.</li>
- <LI>EventProxy first attempts to locate the Variant class using FindClass()</li>
- <LI>Failing that, it looks to see if a variant object had been passed in. If so, it calls class() and goes
- from there. </li>
- <LI>If all that fails, it logs a message and then fails in the spectacular fashion of the previous versions.</li>
- </OL>
- <H2>1.10 behavior</H2>
- The Jacob EventProxy class has been modified so that it takes a different approach towards fixing this problem.
- <OL>
- <LI>All objects that request event notification are now wrapped in a Java InvocationProxy so that a standard
- interface is always presented to the JNI EventProxy object.</li>
- <LI>The EventProxy constructor accepts any Java class. It wraps the class if it is not an InvocationProxy or
- uses just the passed in object if it is an InvocationProxy. The JNI layer talks to the InvocationProxy
- instead of talking directly to the event listener as in previous releases.</li>
- <LI>The Java InvocationProxy has a method on it that will return the Variant class that the EventProxy. The
- JNI code uses this method to acquire the class so that it can call newInstance().</li>
- </OL>
- Developers can receive call back events in JWS other Java launching programs without implementing any additional code. They
- should be aware that their callback methods may need to set the class loader. If they expect to create any objects.:
- <pre>
- Public xxx someHandler(Variant[] foo){
- Thread.currentThread().setContextClassLoader(
- this.getClass().getClassLoader());
- // do something
- }
- </pre>
- <p></p>
- There may still be a dual event queue issue in JWS applications that needs to be looked at.
- <p></p>
- <H2>1.12 Experimental Behavior</H2>
- Release 1.12 adds experimental support for event handlers that accept java objects as parameters to closer match the signature
- of the windows callback. New ActiveXDispatchEvents and ActiveXInvocationProxy operate in tandem in the same way
- as DispatchEvents and InvocationProxy. DispatchEvents overrides getInvocationProxy() to create a new ActiveXInvocationProxy
- in place of the normal InvocationProxy. ActiveXInvocationProxy has its own invoke() method that uses reflection
- to call back using java objects as parameters.
- <p></p>
- Issues with this approach
- <ul>
- <li>Event callbacks that use java signatures do not support parameter modification. Many windows callbacks
- let a user reject an event that is about to happen by modifying one of the parameters. In this situation,
- the old DispatchEvents/InvocationProxy pair must be used instead of the new handlers.</li>
- </ul>
- </body>
- </html>
|