From 45f9603a3e0392cbcd2bf14737d3cbdaea8c88fd Mon Sep 17 00:00:00 2001 From: troggan <> Date: Sun, 17 Oct 2004 18:36:41 +0000 Subject: [PATCH] Initial commit --- jacob/JacobComLifetime.html | 51 + jacob/JacobThreading.html | 410 +++ jacob/LICENSE.TXT | 29 + jacob/META-INF/MANIFEST.MF | 897 ++++++ jacob/README.TXT | 28 + jacob/WhatsNew.html | 114 + jacob/com/jacob/activeX/ActiveXComponent.java | 73 + jacob/com/jacob/com/ComException.java | 88 + jacob/com/jacob/com/ComFailException.java | 65 + jacob/com/jacob/com/ComThread.java | 130 + jacob/com/jacob/com/Dispatch.java | 546 ++++ jacob/com/jacob/com/DispatchEvents.java | 64 + jacob/com/jacob/com/DispatchProxy.java | 65 + jacob/com/jacob/com/EnumVariant.java | 122 + jacob/com/jacob/com/JacobObject.java | 46 + jacob/com/jacob/com/MainSTA.java | 43 + jacob/com/jacob/com/ROT.java | 99 + jacob/com/jacob/com/STA.java | 98 + jacob/com/jacob/com/SafeArray.java | 247 ++ jacob/com/jacob/com/Variant.java | 368 +++ jacob/com/jacob/com/WrongThreadException.java | 37 + jacob/jacob.dll | Bin 0 -> 94208 bytes jacob/jacob.jar | Bin 0 -> 17173 bytes jacob/jni/ComThread.cpp | 57 + jacob/jni/ComThread.h | 30 + jacob/jni/Dispatch.cpp | 422 +++ jacob/jni/Dispatch.h | 53 + jacob/jni/DispatchEvents.cpp | 311 +++ jacob/jni/DispatchEvents.h | 39 + jacob/jni/DispatchProxy.cpp | 116 + jacob/jni/DispatchProxy.h | 37 + jacob/jni/EnumVariant.cpp | 137 + jacob/jni/EnumVariant.h | 46 + jacob/jni/EventProxy.cpp | 163 ++ jacob/jni/EventProxy.h | 107 + jacob/jni/README.txt | 17 + jacob/jni/STA.cpp | 73 + jacob/jni/STA.h | 29 + jacob/jni/SafeArray.cpp | 2438 +++++++++++++++++ jacob/jni/SafeArray.h | 693 +++++ jacob/jni/StdAfx.cpp | 41 + jacob/jni/StdAfx.h | 32 + jacob/jni/Variant.cpp | 1145 ++++++++ jacob/jni/Variant.h | 613 +++++ jacob/jni/jacob.dll | Bin 0 -> 94208 bytes jacob/jni/jacob.exp | Bin 0 -> 36752 bytes jacob/jni/jacob.lib | Bin 0 -> 61978 bytes jacob/jni/makefile | 51 + jacob/jni/util.cpp | 69 + jacob/jni/util.h | 8 + jacob/makefile | 18 + jacob/samples/README.txt | 8 + jacob/samples/ado/ADO_README.txt | 88 + jacob/samples/ado/Command.java | 120 + jacob/samples/ado/CommandTypeEnum.java | 12 + jacob/samples/ado/Connection.java | 180 ++ jacob/samples/ado/Field.java | 124 + jacob/samples/ado/Fields.java | 50 + jacob/samples/ado/Recordset.java | 411 +++ jacob/samples/ado/ms/README | 3 + jacob/samples/ado/ms/testms.java | 64 + jacob/samples/ado/test.java | 62 + jacob/samples/applet/AppTest.html | 8 + jacob/samples/applet/AppTest.java | 37 + jacob/samples/servlet/JacobScript.java | 73 + jacob/samples/servlet/readme.txt | 44 + jacob/samples/test/Access.java | 89 + jacob/samples/test/DispatchTest.java | 40 + jacob/samples/test/IETest.java | 115 + jacob/samples/test/MathProj/Math.cls | 37 + jacob/samples/test/MathProj/MathTest.dll | Bin 0 -> 24576 bytes jacob/samples/test/MathProj/MathTest.exp | Bin 0 -> 988 bytes jacob/samples/test/MathProj/MathTest.lib | Bin 0 -> 2616 bytes jacob/samples/test/MathProj/MathTest.vbp | 35 + jacob/samples/test/MathProj/MathTest.vbw | 1 + jacob/samples/test/MathProj/README | 1 + jacob/samples/test/Outlook.java | 69 + jacob/samples/test/ScriptTest.bat | 2 + jacob/samples/test/ScriptTest.java | 57 + jacob/samples/test/ScriptTest2.java | 98 + jacob/samples/test/ScriptTest3.java | 68 + jacob/samples/test/atl/MultiFace.java | 32 + jacob/samples/test/atl/MultiFace/Face.cpp | 67 + jacob/samples/test/atl/MultiFace/Face.h | 63 + jacob/samples/test/atl/MultiFace/Face.rgs | 23 + .../samples/test/atl/MultiFace/MultiFace.aps | Bin 0 -> 3584 bytes .../samples/test/atl/MultiFace/MultiFace.cpp | 72 + .../samples/test/atl/MultiFace/MultiFace.def | 9 + .../samples/test/atl/MultiFace/MultiFace.dsp | 323 +++ .../samples/test/atl/MultiFace/MultiFace.dsw | 29 + jacob/samples/test/atl/MultiFace/MultiFace.h | 571 ++++ .../samples/test/atl/MultiFace/MultiFace.idl | 70 + .../samples/test/atl/MultiFace/MultiFace.ncb | Bin 0 -> 58368 bytes .../samples/test/atl/MultiFace/MultiFace.opt | Bin 0 -> 53760 bytes .../samples/test/atl/MultiFace/MultiFace.plg | 48 + jacob/samples/test/atl/MultiFace/MultiFace.rc | 125 + .../samples/test/atl/MultiFace/MultiFace.tlb | Bin 0 -> 2424 bytes .../samples/test/atl/MultiFace/MultiFace_i.c | 56 + .../samples/test/atl/MultiFace/MultiFace_p.c | 570 ++++ .../test/atl/MultiFace/MultiFaceps.def | 11 + .../samples/test/atl/MultiFace/MultiFaceps.mk | 16 + jacob/samples/test/atl/MultiFace/StdAfx.cpp | 12 + jacob/samples/test/atl/MultiFace/StdAfx.h | 27 + jacob/samples/test/atl/MultiFace/dlldata.c | 38 + jacob/samples/test/atl/MultiFace/resource.h | 18 + jacob/samples/test/atl/readme.txt | 14 + jacob/samples/test/foo.foo | Bin 0 -> 80 bytes jacob/samples/test/foo.ser | Bin 0 -> 147 bytes jacob/samples/test/jacobtest.xls | Bin 0 -> 91136 bytes jacob/samples/test/math.java | 38 + jacob/samples/test/sa_dispatch.java | 41 + jacob/samples/test/sa_test.java | 58 + jacob/samples/test/safearray.java | 61 + jacob/samples/test/sample2.mdb | Bin 0 -> 90112 bytes jacob/samples/test/speed.java | 18 + jacob/samples/test/test.java | 276 ++ jacob/samples/test/varSerTest.java | 50 + jacob/samples/test/variant_test.java | 23 + jacob/todo.txt | 1 + jacob/vstudio/jacob/jacob.dsp | 190 ++ jacob/vstudio/jacob/jacob.dsw | 29 + jacob/vstudio/jacob/jacob.ncb | Bin 0 -> 132096 bytes jacob/vstudio/jacob/jacob.opt | Bin 0 -> 53760 bytes jacob/vstudio/jacob/jacob.plg | 66 + 124 files changed, 15306 insertions(+) create mode 100644 jacob/JacobComLifetime.html create mode 100644 jacob/JacobThreading.html create mode 100644 jacob/LICENSE.TXT create mode 100644 jacob/META-INF/MANIFEST.MF create mode 100644 jacob/README.TXT create mode 100644 jacob/WhatsNew.html create mode 100644 jacob/com/jacob/activeX/ActiveXComponent.java create mode 100644 jacob/com/jacob/com/ComException.java create mode 100644 jacob/com/jacob/com/ComFailException.java create mode 100644 jacob/com/jacob/com/ComThread.java create mode 100644 jacob/com/jacob/com/Dispatch.java create mode 100644 jacob/com/jacob/com/DispatchEvents.java create mode 100644 jacob/com/jacob/com/DispatchProxy.java create mode 100644 jacob/com/jacob/com/EnumVariant.java create mode 100644 jacob/com/jacob/com/JacobObject.java create mode 100644 jacob/com/jacob/com/MainSTA.java create mode 100644 jacob/com/jacob/com/ROT.java create mode 100644 jacob/com/jacob/com/STA.java create mode 100644 jacob/com/jacob/com/SafeArray.java create mode 100644 jacob/com/jacob/com/Variant.java create mode 100644 jacob/com/jacob/com/WrongThreadException.java create mode 100644 jacob/jacob.dll create mode 100644 jacob/jacob.jar create mode 100644 jacob/jni/ComThread.cpp create mode 100644 jacob/jni/ComThread.h create mode 100644 jacob/jni/Dispatch.cpp create mode 100644 jacob/jni/Dispatch.h create mode 100644 jacob/jni/DispatchEvents.cpp create mode 100644 jacob/jni/DispatchEvents.h create mode 100644 jacob/jni/DispatchProxy.cpp create mode 100644 jacob/jni/DispatchProxy.h create mode 100644 jacob/jni/EnumVariant.cpp create mode 100644 jacob/jni/EnumVariant.h create mode 100644 jacob/jni/EventProxy.cpp create mode 100644 jacob/jni/EventProxy.h create mode 100644 jacob/jni/README.txt create mode 100644 jacob/jni/STA.cpp create mode 100644 jacob/jni/STA.h create mode 100644 jacob/jni/SafeArray.cpp create mode 100644 jacob/jni/SafeArray.h create mode 100644 jacob/jni/StdAfx.cpp create mode 100644 jacob/jni/StdAfx.h create mode 100644 jacob/jni/Variant.cpp create mode 100644 jacob/jni/Variant.h create mode 100644 jacob/jni/jacob.dll create mode 100644 jacob/jni/jacob.exp create mode 100644 jacob/jni/jacob.lib create mode 100644 jacob/jni/makefile create mode 100644 jacob/jni/util.cpp create mode 100644 jacob/jni/util.h create mode 100644 jacob/makefile create mode 100644 jacob/samples/README.txt create mode 100644 jacob/samples/ado/ADO_README.txt create mode 100644 jacob/samples/ado/Command.java create mode 100644 jacob/samples/ado/CommandTypeEnum.java create mode 100644 jacob/samples/ado/Connection.java create mode 100644 jacob/samples/ado/Field.java create mode 100644 jacob/samples/ado/Fields.java create mode 100644 jacob/samples/ado/Recordset.java create mode 100644 jacob/samples/ado/ms/README create mode 100644 jacob/samples/ado/ms/testms.java create mode 100644 jacob/samples/ado/test.java create mode 100644 jacob/samples/applet/AppTest.html create mode 100644 jacob/samples/applet/AppTest.java create mode 100644 jacob/samples/servlet/JacobScript.java create mode 100644 jacob/samples/servlet/readme.txt create mode 100644 jacob/samples/test/Access.java create mode 100644 jacob/samples/test/DispatchTest.java create mode 100644 jacob/samples/test/IETest.java create mode 100644 jacob/samples/test/MathProj/Math.cls create mode 100644 jacob/samples/test/MathProj/MathTest.dll create mode 100644 jacob/samples/test/MathProj/MathTest.exp create mode 100644 jacob/samples/test/MathProj/MathTest.lib create mode 100644 jacob/samples/test/MathProj/MathTest.vbp create mode 100644 jacob/samples/test/MathProj/MathTest.vbw create mode 100644 jacob/samples/test/MathProj/README create mode 100644 jacob/samples/test/Outlook.java create mode 100644 jacob/samples/test/ScriptTest.bat create mode 100644 jacob/samples/test/ScriptTest.java create mode 100644 jacob/samples/test/ScriptTest2.java create mode 100644 jacob/samples/test/ScriptTest3.java create mode 100644 jacob/samples/test/atl/MultiFace.java create mode 100644 jacob/samples/test/atl/MultiFace/Face.cpp create mode 100644 jacob/samples/test/atl/MultiFace/Face.h create mode 100644 jacob/samples/test/atl/MultiFace/Face.rgs create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.aps create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.cpp create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.def create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.dsp create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.dsw create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.h create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.idl create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.ncb create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.opt create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.plg create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.rc create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace.tlb create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace_i.c create mode 100644 jacob/samples/test/atl/MultiFace/MultiFace_p.c create mode 100644 jacob/samples/test/atl/MultiFace/MultiFaceps.def create mode 100644 jacob/samples/test/atl/MultiFace/MultiFaceps.mk create mode 100644 jacob/samples/test/atl/MultiFace/StdAfx.cpp create mode 100644 jacob/samples/test/atl/MultiFace/StdAfx.h create mode 100644 jacob/samples/test/atl/MultiFace/dlldata.c create mode 100644 jacob/samples/test/atl/MultiFace/resource.h create mode 100644 jacob/samples/test/atl/readme.txt create mode 100644 jacob/samples/test/foo.foo create mode 100644 jacob/samples/test/foo.ser create mode 100644 jacob/samples/test/jacobtest.xls create mode 100644 jacob/samples/test/math.java create mode 100644 jacob/samples/test/sa_dispatch.java create mode 100644 jacob/samples/test/sa_test.java create mode 100644 jacob/samples/test/safearray.java create mode 100644 jacob/samples/test/sample2.mdb create mode 100644 jacob/samples/test/speed.java create mode 100644 jacob/samples/test/test.java create mode 100644 jacob/samples/test/varSerTest.java create mode 100644 jacob/samples/test/variant_test.java create mode 100644 jacob/todo.txt create mode 100644 jacob/vstudio/jacob/jacob.dsp create mode 100644 jacob/vstudio/jacob/jacob.dsw create mode 100644 jacob/vstudio/jacob/jacob.ncb create mode 100644 jacob/vstudio/jacob/jacob.opt create mode 100644 jacob/vstudio/jacob/jacob.plg diff --git a/jacob/JacobComLifetime.html b/jacob/JacobComLifetime.html new file mode 100644 index 0000000..7f1a3a7 --- /dev/null +++ b/jacob/JacobComLifetime.html @@ -0,0 +1,51 @@ +

COM Object Lifetime in JACOB

+

+

introduction

+

+JACOB Version 1.7 implements a new +Threading Model that is more +compatible with COM apartments. There is also an incompatibility +between the Java object lifetime model and that of COM objects. +COM Objects live and die by their reference count, whereas Java +objects are collected by the Garbage Collector (GC) based on algortihms +that are hidden from the user. +

COM Object Lifetime in JACOB Prior to Version 1.7

+

+In version 1.6 and earlier, JACOB objects which wrapped COM objects +had finalize() methods that would call a native +release method which would call a COM Release. +

+This has many problems. For one thing, the GC may take a long time to +kick in and resource consumption may grow. However, the more problematic +issue is that finalizers are called from a separate thread, and, as was +discussed in the Threading Model +document, this can result in COM errors if the object is running in an +STA. Even if the object is running in an MTA, the finalizer may decide +to run after we have terminated the thread that holds the component, in +which case we would get fatal errors and crashes. +

COM Object Lifetime in JACOB in Version 1.7

+

+In Version 1.7, all JACOB objects which wrap COM objects extend +com.jacob.com.JacobObject. This object has some special +code to register itself with a com.jacob.com.ROT object +which represents a Running Object Table (ROT). This table maps a +Thread to the set of JacobObjects created in that thread. Therefore, +when you call ComThread.Release(), the ROT checks whether +that thread has created any objects, and these objects are released +by calling their native release method (which is public). +

+This lifetime management method ties the lifecycle to the thread's +lifecycle rather than the GC. The JacobObject's still have finalizers, +but they will typically not perform the native release +since that has already been called. The native release +methods were written such that you can call them multiple times without +worrying - since they zero out the native pointer when called the first +time. +

+If you choose to call release methods on your objects +yourself, that is allowed. In that case, when the thread is released +the release calls will be no-ops. +

+It becomes important for you to call ComThread.Release() +on any thread before you allow it to exit, otherwise you may get +some random crashes later on in your code. diff --git a/jacob/JacobThreading.html b/jacob/JacobThreading.html new file mode 100644 index 0000000..7960551 --- /dev/null +++ b/jacob/JacobThreading.html @@ -0,0 +1,410 @@ +

COM Apartments in JACOB

+

+

introduction

+

+The COM model for Threading differs from the Java model. +In COM, each component can declare whether or not it support +multi-threading. + +You can find some basic information about COM threading at: +

+ +http://www.execpc.com/~gopalan/com/com_threading.html +

+ +www.microsoft.com/msj/0297/apartment/apartment.htm +

+ +http://www.cswl.com/whiteppr/white/multithreading.html + +

+The term Single Threaded Apartment (STA) refers to a thread +where all COM objects created in that thread are +single-threaded. This can manifest itself in two ways: +
+Either all calls into that component are made from the same thread +that created the component +
+OR any call that is made from another thread gets serialized by COM. +This serialization of calls is done by using a Windows message loop and +posting messages to a hidden window (I'm not kidding). The way COM +achieves this is by requiring any other thread to make calls through +a local Proxy object rather than the original object (more on this +when we discuss the JACOB DispatchProxy class). +

+What does this mean for a Java application? If you are using a component +that declares itself as ThreadingModel "Apartment" (you can +find this out by looking in the registry under its CLSID), and you plan +to create, use and destroy this component in one thread - then you are +following the rules of an STA and you can declare the thread as an +STA thread. +

+On the other hand, if you need to make method calls from another thread +(e.g. in a servlet) then you have a few choices. Either you +create the component in its own STA, by extending +com.jacob.com.STA, and use the +com.jacob.com.DispatchProxy class to pass the Dispatch +pointer between threads, or you can declare your thread as an MTA +thread. In that case, COM will make +the cross-thread calls into the STA that is running your component. +If you create an Apartment threaded component in the MTA, +COM will automatically create an STA for you and put your +component in there, and then marshall all the calls. +

+This brings us to the notion of a Main STA. COM requires that +if there is any Apartment threaded component in your application, then +the first STA created is tagged as the Main STA. COM uses the +Main STA to create all the Apartment threaded components that are +created from an MTA thread. The problem is that if you have already +created an STA, then COM will pick that as the Main STA, and if you +ever exit that thread - the whole application will exit. + +

COM Threads in JACOB Prior to Version 1.7

+

+Up until version 1.7 of JACOB, there was only one model available +in JACOB: +

+

+The reason for the change in default was that tagging a Java thread +as an STA can cause problems. Any Java Swing application, as well as +servlets and applets need to be able to make calls from multiple +threads. If you try to make COM method calls across STA threads - it +will fail! +

+In most cases, the default chosen by JACOB 1.6 (MTA) works fine, however +there are some notable exceptions that have caused people grief. One +such exception is in the case of MAPI. It turns out that if you try to +create a MAPI object from an MTA thread - it simply fails and exits. +This has caused some people to recompile JACOB 1.6 back with the STA +default. +

+There is another problem with MTA threads: when you are using Apartment +threaded components, we already noted that COM will create the +components in the Main STA. If one doesn't exist, COM will create it. +However, this means that all Apartment threaded components will +be created in the same STA. This creates a bottleneck, and a +dependency between unrelated components. Also, if that STA exits, then +all components are destroyed and the application will likely crash. + +

COM Threads in JACOB Version 1.7

+

+In Version 1.7 we have added finer grained control to allow the +Java programmer to control how COM creates its components. +Unfortunately, this means that you need to have a pretty good +understanding of the dark and mystical subject of COM Apartments. +There are a few different cases you need to consider: +

Default

+

+If you simply run code that was created in Version 1.6 and ignore +the COM threading issue, then you will get the same behavior as in 1.6: +Each java thread will be an MTA thread, and all Apartment threaded +components will be created by COM in its own Main STA. This typically +works for most applications (exceptions noted above). +

Create Your Own Apartment

+

+To declare an MTA thread use the following template: +
+

+
+ComThread.InitMTA();
+...
+...
+ComThread.Release();
+
+ +
+If you want JACOB to create its own Main STA (rather than having COM +choose an STA for you), then you should use: +
+ +
+Thread 1:
+ComThread.InitMTA(true); // a true tells JACOB to create a Main STA
+...
+...
+ComThread.Release();
+...
+Thread 2:
+ComThread.InitMTA(); 
+...
+...
+ComThread.Release();
+...
+...
+ComThread.quitMainSTA();
+
+
+
+In this case, you can also create the Main STA explicitly: +
+ +
+ComThread.startMainSTA();
+...
+...
+Thread 1:
+ComThread.InitMTA();
+...
+...
+ComThread.Release();
+...
+Thread 2:
+ComThread.InitMTA(); 
+...
+...
+ComThread.Release();
+...
+...
+ComThread.quitMainSTA();
+
+
+
+In the latter case, all Apartment threaded components will be created in +JACOB's main STA. This still has all the problems of components +sharing the same Main STA and creating a bottleneck. To avoid that, +you can also create STA threads yourself: +
+ +
+ComThread.startMainSTA();
+...
+...
+Thread 1:
+ComThread.InitSTA();
+...
+...
+ComThread.Release();
+...
+Thread 2:
+ComThread.InitMTA(); 
+...
+...
+ComThread.Release();
+...
+...
+ComThread.quitMainSTA();
+
+
+
+In this example, thread 1 is an STA and thread 2 is an MTA. You could +omit the call to ComThread.startMainSTA(), but if you do, then COM will +make the first STA your main one, and then if you exit that thread, +the application will crash. +

+Actually, Thread 1 is almost an STA. It's lacking a windows +message loop. So, this type of STA is fine as long as you are creating +a component and using it in the same thread, and not makind event +callbacks. +

JACOB's STA Class

+

+If you want to create an true STA where you can create a component and +then let other threads call methods on it, then you need a windows +message loop. JACOB provides a class called: +com.jacob.com.STA which does exactly this. + +

+public class com.jacob.com.STA extends java.lang.Thread 
+{
+    public com.jacob.com.STA();
+    public boolean OnInit(); // you override this
+    public void OnQuit(); // you override this
+    public void quit();  // you can call this from ANY thread
+}
+
+ +

+The STA class extends +java.lang.Thread and it provides you with two methods +that you can override: OnInit and OnQuit. +These methods are called from the thread's run method +so they will execute in the new thread. These methods allow you to +create COM components (Dispatch objects) and release them. +To create an STA, you subclass it and override the OnInit. +

+The quit method is the only other method that +can be called from any thread. This method uses the Win32 function +PostThreadMessage to force the STA's windows message loop +to exit, thereby terminating the thread. +

+You will then need to make calls into the component that is running +in the STA thread. If you simply try to make calls from another thread +on a Dispatch object created in the STA thread, you will get a COM +Exception. For more details see: + +Don Box 'Effective COM' Rule 29: Don't Access raw +interface pointers across apartment boundaries. +

The DispatchProxy Class

+Since you cannot call methods directly on a Dispatch object created +in another STA JACOB provides a method for the class that created +the Dispatch object to marshal it to your thread. This is done via +the com.jacob.com.DispatchProxy class. + +
+public class DispatchProxy extends JacobObject {
+    public DispatchProxy(Dispatch);
+    public Dispatch toDispatch();
+
+    public native void release();
+    public void finalize();
+}
+
+
+

+This class works as follows: the thread that created the Dispatch +object constructs an instance of DispatchProxy(Dispatch) with the +Dispatch as a parameter. This instance can then be accessed from +another thread, which will invoke its toDispatch method +proxy as if it were local to your thread. COM will do the inter-thread +marshalling transparently. +

+The following example is part of samples/test/ScriptTest2.java in the +JACOB distribution. It shows how you can create the ScriptControl +in one STA thread and make method calls on it from another: + +

+import com.jacob.com.*;
+import com.jacob.activeX.*;
+
+class ScriptTest2 extends STA
+{
+  public static ActiveXComponent sC;
+  public static Dispatch sControl = null;
+  public static DispatchProxy sCon = null;
+
+  public boolean OnInit()
+  {
+     try
+     {
+       System.out.println("OnInit");
+       System.out.println(Thread.currentThread());
+       String lang = "VBScript";
+
+       sC = new ActiveXComponent("ScriptControl");
+       sControl = (Dispatch)sC.getObject();
+
+       // sCon can be called from another thread
+       sCon = new DispatchProxy(sControl);
+
+       Dispatch.put(sControl, "Language", lang);
+       return true;
+     }
+     catch (Exception e)
+     {
+       e.printStackTrace();
+       return false;
+     }
+  }
+
+  public void OnQuit()
+  {
+     System.out.println("OnQuit");
+  }
+
+  public static void main(String args[]) throws Exception
+  {
+    try {
+      ComThread.InitSTA();
+      ScriptTest2 script = new ScriptTest2();
+      Thread.sleep(1000);
+
+      // get a thread-local Dispatch from sCon
+      Dispatch sc = sCon.toDispatch();
+
+      // call a method on the thread-local Dispatch obtained
+      // from the DispatchProxy. If you try to make the same
+      // method call on the sControl object - you will get a
+      // ComException.
+      Variant result = Dispatch.call(sc, "Eval", args[0]);
+      System.out.println("eval("+args[0]+") = "+ result);
+      script.quit();
+      System.out.println("called quit");
+    } catch (ComException e) {
+      e.printStackTrace();
+    }
+    finally
+    {
+      ComThread.Release();
+    }
+  }
+}
+
+ +

+You can try to modify the Dispatch.call invocation in +the main thread to use sControl directly, and you will see +that it fails. Notice that once we construct the ScriptTest2 object +in the main thread, we sleep for a second to allow the other thread +time to initialize itself. +

+The STA thread calls sCon = new DispatchProxy(sControl); +to save a global reference to the DispatchProxy that represents the +sControl object. The main thread then calls: +Dispatch sc = sCon.toDispatch(); to get a local Dispatch +proxy out of the DispatchProxy object. +

+At most one(!) +thread can call toDispatch(), and the call can be made only once. +This is because a IStream object is used to pass the proxy, and +it is only written once and closed when you read it. +If you need multiple threads to access a Dispatch pointer, then +create that many DispatchProxy objects. For more details please +refer to the Don Box reference above. + + +

Recommended Procedure

+