Prepare source files for merge

This commit is contained in:
2014-12-07 09:44:25 +00:00
parent f0204690cc
commit e2eae0eac4
174 changed files with 0 additions and 22635 deletions

View File

@@ -1,144 +0,0 @@
<HTML>
<BODY>
<h1> Overview </h1>
JACOB is built on windows machines using ANT, most commonly from inside of Eclipse.
The main steps for getting a working Jacob build are:
<ol>
<li>Check out the source code or unpack the source zip file from sourceforge</li>
<li>Install the Development Environment</li>
<li>Configure the build by creating a <i>compilation_tools.properties</i> file.</li>
<li>Run Eclipse and load the project into eclipse</li>
<li>Open the build.xml file in Eclipse and run the default ant target </li>
</ol>
<p>
<h1> Repository Organization </h1>
<p>
Unpack the source archive zip file or check the files out of CVS into d:\jacob
or some other familiar place. Source Java and JNI files are located in seperate
packages from the unit tests and the samples.
<p>
<ul>
<li>docs: documentation
<li>jni: c++ code
<li>lib: libraries needed to compile unit tests
<li>release: a directory built by the ant script where jacob is constructed
<li>samples: sample programs
<li>src: Jacob Java source files
<li>unittest: JUnit 3.8.1 unit test programs. Run from the test target in build.xml
<li>vstudio: some out of date VC++ project files
<li>bulid.xml: the ant build script. It can be run from inside Eclipse
</ul>
<p>
The Servlet examples that required j2ee libraries to compile have temporarily
been removed.
<p>
<H1>Development Environment</h1>
The simplest build environment includes MS Visual C++ 8.0 (Studio 2005),
Eclipse 3.3 with the C/C++ module and JDK 1.5.
In that situation, you would just create the <i>compilation_tools.properties</i>
using the example build.xml as a template.
<UL>
<li> Microsoft Visual C++ 8.0 and it's included library. (to C:\ProgramFiles in my case)
<li> Eclipse 3.4 or later from www.eclipse.org as the Java IDE.
<li> Eclipse 3.4 or later with the C/C++ plugin can be used for C coding in place of VC++ IDE.
<li> Java JDK 1.5 (1.15 was built using 1.5.0.16)
</ul>
<p>
<p>
<table>
<TR><TD>Release</TD><TD>C Version</TD><TD>Java Version</TD><TD>ANT Version</TD><TD>Eclipse Version Used</TD><TD>generated DLLs</TD></TR>
<TR><TD>up to 1.6</TD><TD>VC 98 (6.0)</TD><TD>?</TD><td>MAKE</td><TD>?</TD><TD>32 bit</TD></TR>
<TR><TD>1.7</TD><TD>VC 98 (6.0)</TD><TD>1.4</TD><td>1.?</td><TD>?</TD><TD>32 bit</TD></TR>
<TR><TD>1.8</TD><TD>VC 98 (6.0)</TD><TD>1.4</TD><td>1.?</td><TD>?</TD><TD>32 bit</TD></TR>
<TR><TD>1.9</TD><TD>VC 98 (6.0)</TD><TD>1.4</TD><td>1.?</td><TD>?</TD><TD>32 bit</TD></TR>
<TR><TD>1.10</TD><TD>VC 98 (6.0)</TD><TD>1.4</TD><td>1.?</td><TD>3.??</TD><TD>32 bit</TD></TR>
<TR><TD>1.11</TD><TD>VC 98 (6.0) & 2003 64bit libs</TD><TD>1.4.?</TD><td>1.6.?</td><TD>3.2.1</TD><TD>32 and 64 bit</TD></TR>
<TR><TD>1.12</TD><TD>VC 98 (6.0) & 2003 64bit libs</TD><TD>1.4.2</TD><td>1.6.5</td><TD>3.2.2</TD><TD>32 and 64 bit</TD></TR>
<TR><TD>1.13</TD><TD>VC 2005</TD><TD>1.4.2</TD><TD>1.7.0</TD><TD>3.3</TD><TD>32 and 64 bit</TD></TR>
<TR><TD>1.14</TD><TD>VC 2005</TD><TD>1.5.0</TD><TD>1.7.0</TD><TD>3.3</TD><TD>32 and 64 bit</TD></TR>
<TR><TD>1.15</TD><TD>VC 2005</TD><TD>1.5.0</TD><TD>1.7.0</TD><TD>3.4</TD><TD>32 and 64 bit</TD></TR>
</table>
Microsoft Visual C++ 8.0 supports 64 bit builds. so no additional tools are required.
<p>
<H1>Build Process</H1>
The build process is based on ANT.
You can run ANT from inside of eclipse or from the command line.
The ant process is driven off of a configuration file named
<code>compilation_tools.properties</code> that describes the locations of the JDK and Microsoft
C++ tools. The <code>build.xml</code> file in the root directory contains examples of the contents
of this file.
<p>
There are two main ant targets.
<UL>
<li>"default" executes the following steps when using the default target.
<UL>
<li> Build the Java code
<li> Build the jni code
<li> create the dll
<li> create jar file
</UL>
<li>"package" runs the above listed steps and then
<UL>
<LI>builds the javadoc
<LI>builds a source zip
<li>builds a binary zip with the javadoc
</UL>
</UL>
<p>
<H1>Eclipse Java IDE</h1>
<p>
Eclipse users have to do some minor tweaks to their project if they
want to use the integrated build process. This is because the unit
tests are files located in the "unittest" directory while
the project source files themselves are in "src" the root directory.
By default, eclipse will add the entire project as source. This
messes up the package naming. In addition, the build directory should be
set to be the same place the ANT build puts the compiled java classes.
A couple small tweaks to the build path fix these problems:
<p>
Open up the project properties and go to the "Java Build Path" properties panel.
<ul>
<li> Remove the root of the project from the build path</li>
<li> Add folders <code>samples</code>, <code>src</code> and <code>unittest</code>
to the build path in the Source tab.</li>
<li> Exclude *.txt from each of the newly added folders. </li>
<li> Set the default build output directory to <code>jacob-project/release/java</code></li>
</ul>
<h2> Troubleshooting Build Problems </h2>
<ul>
<li>
Symptom: The jar is built but no dlls were compiled.<p>
Problem: compilation_tools.properties does not have the correct location for the Microsoft tools.<p>
</li>
<li>
Sympton: Can't find jni.h or can't find C++ compiler<p>
Problem: compilation_tools.properties configured incorrectly. Either
paths are wrong or the separator is wrong. It requires two backslashes for a separator.<p>
</li>
</ul>
<h1> Running Samples and Tests </h1>
Samples and JUnit test programs can be found in the source jar or in CVS. The programs
can be run from a bat file or from inside the Eclipse IDE. The java library
path variable must be set to include the directory the jacob.dll is in. The
simplest way to do that is to add it as a command line option. The following
assume that your jacob development area is located in c:\dev\jacob:
<pre>
-Djava.library.path=c:/dev/jacob/release/x86
-Dcom.jacob.autogc=false
-Dcom.jacob.debug=false
-Xcheck:jni
</pre>
<p>
JUnit test programs can be individually run from inside eclipse or en-masse
via the <code>ant test</code> target.
Last Modified 10/2008 1.15
</BODY>
</HTML>

View File

@@ -1,88 +0,0 @@
<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>The application continues on doing other work.
<LI>Some time later, the MS application takes some action and initiates the event callback.
<LI>The Java VM receives the event and spins up a new thread to handle it.
<LI>The Jacob jni EventProxy in the dll is called by the VM.
<LI>The Jacob jni EventProxy creates Variant objects to handle the parameters of the passed in event.
<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>The Java InvocationProxy uses reflection to map the event name to a method name with the exact same name.
<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>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.
</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<61>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>EventProxy first attempts to locate the Variant class using FindClass()
<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>If all that fails, it logs a message and then fails in the spectacular fashion of the previous versions.
</OL>
<p>
<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>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>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().
</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>
There may still be a dual event queue issue in JWS applications that needs to be looked at.
<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>
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.
</ul>
</body>
</html>

View File

@@ -1,51 +0,0 @@
<H1>COM Object Lifetime in JACOB</H1>
<p>
<H2>introduction</H2>
<p>
JACOB Version 1.7 implements a new
<a href="JacobThreading.html">Threading Model</a> 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.
<H2>COM Object Lifetime in JACOB Prior to Version 1.7</H2>
<p>
In version 1.6 and earlier, JACOB objects which wrapped COM objects
had <code>finalize()</code> methods that would call a native
<code>release</code> method which would call a COM <code>Release</code>.
<p>
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 <a href="JacobThreading.html">Threading Model</a>
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.
<H2>COM Object Lifetime in JACOB in Version 1.7</H2>
<p>
In Version 1.7, all JACOB objects which wrap COM objects extend
<code>com.jacob.com.JacobObject</code>. This object has some special
code to register itself with a <code>com.jacob.com.ROT</code> 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 <code>ComThread.Release()</code>, the ROT checks whether
that thread has created any objects, and these objects are released
by calling their native <code>release</code> method (which is public).
<p>
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 <code>release</code>
since that has already been called. The native <code>release</code>
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.
<p>
If you choose to call <code>release</code> methods on your objects
yourself, that is allowed. In that case, when the thread is released
the release calls will be no-ops.
<p>
It becomes important for you to call <code>ComThread.Release()</code>
on any thread before you allow it to exit, otherwise you may get
some random crashes later on in your code.

View File

@@ -1,410 +0,0 @@
<H1>COM Apartments in JACOB</H1>
<p>
<H2>introduction</H2>
<p>
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:
<p>
<a href="http://www.execpc.com/~gopalan/com/com_threading.html">
http://www.execpc.com/~gopalan/com/com_threading.html</a>
<p>
<a href="www.microsoft.com/msj/0297/apartment/apartment.htm">
www.microsoft.com/msj/0297/apartment/apartment.htm</a>
<p>
<a href="http://www.cswl.com/whiteppr/white/multithreading.html">
http://www.cswl.com/whiteppr/white/multithreading.html
</a>
<p>
The term <b>Single Threaded Apartment (STA)</b> refers to a thread
where all COM objects created in that thread are
single-threaded. This can manifest itself in two ways:
<br>
Either all calls into that component are made from the same thread
that created the component
<br>
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).
<p>
What does this mean for a Java application? If you are using a component
that declares itself as <b>ThreadingModel "Apartment"</b> (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.
<p>
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
<code>com.jacob.com.STA</code>, and use the
<code>com.jacob.com.DispatchProxy</code> 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.
<p>
This brings us to the notion of a <b>Main STA</b>. COM requires that
if there is any Apartment threaded component in your application, then
the first STA created is tagged as the <b>Main STA</b>. 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.
<H2>COM Threads in JACOB Prior to Version 1.7</H2>
<p>
Up until version 1.7 of JACOB, there was only one model available
in JACOB:
<ul>
<li>
Before version 1.6: All threads were automatically initialized as STAs.
</li>
<li>
In version 1.6: All threads were automatically initialized as MTAs.
</li>
</ul>
<p>
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!
<p>
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.
<p>
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 <b>all</b> Apartment threaded components will
be created in the <b>same STA</b>. 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.
<H2>COM Threads in JACOB Version 1.7</H2>
<p>
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:
<H3>Default</H3>
<p>
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).
<H3>Create Your Own Apartment</H3>
<p>
To declare an MTA thread use the following template:
<br>
<pre>
<code>
ComThread.InitMTA();
...
...
ComThread.Release();
</pre>
</code>
<br>
If you want JACOB to create its own Main STA (rather than having COM
choose an STA for you), then you should use:
<br>
<code>
<pre>
Thread 1:
ComThread.InitMTA(true); // a true tells JACOB to create a Main STA
...
...
ComThread.Release();
...
Thread 2:
ComThread.InitMTA();
...
...
ComThread.Release();
...
...
ComThread.quitMainSTA();
</pre>
</code>
<br>
In this case, you can also create the Main STA explicitly:
<br>
<code>
<pre>
ComThread.startMainSTA();
...
...
Thread 1:
ComThread.InitMTA();
...
...
ComThread.Release();
...
Thread 2:
ComThread.InitMTA();
...
...
ComThread.Release();
...
...
ComThread.quitMainSTA();
</pre>
</code>
<br>
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:
<br>
<code>
<pre>
ComThread.startMainSTA();
...
...
Thread 1:
ComThread.InitSTA();
...
...
ComThread.Release();
...
Thread 2:
ComThread.InitMTA();
...
...
ComThread.Release();
...
...
ComThread.quitMainSTA();
</pre>
</code>
<br>
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.
<p>
Actually, Thread 1 is <i>almost</i> 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.
<H3>JACOB's STA Class</H3>
<p>
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:
<code>com.jacob.com.STA</code> which does exactly this.
<code>
<pre>
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
}
</pre>
</code>
<p>
The STA class extends
<code>java.lang.Thread</code> and it provides you with two methods
that you can override: <code>OnInit</code> and <code>OnQuit</code>.
These methods are called from the thread's <code>run</code> 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.
<p>
The <code>quit</code> method is the <b>only</b> other method that
can be called from any thread. This method uses the Win32 function
<code>PostThreadMessage</code> to force the STA's windows message loop
to exit, thereby terminating the thread.
<p>
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:
<a href="http://www.develop.com/effectivecom">
Don Box 'Effective COM' Rule 29</a>: Don't Access raw
interface pointers across apartment boundaries.
<H3>The DispatchProxy Class</H3>
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 <code>com.jacob.com.DispatchProxy</code> class.
<code>
<pre>
public class DispatchProxy extends JacobObject {
public DispatchProxy(Dispatch);
public Dispatch toDispatch();
public native void release();
public void finalize();
}
</code>
</pre>
<p>
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 <code>toDispatch</code> method
proxy as if it were local to your thread. COM will do the inter-thread
marshalling transparently.
<p>
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:
<code>
<pre>
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();
}
}
}
</pre>
</code>
<p>
You can try to modify the <code>Dispatch.call</code> invocation in
the main thread to use <code>sControl</code> 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.
<p>
The STA thread calls <code>sCon = new DispatchProxy(sControl);</code>
to save a global reference to the DispatchProxy that represents the
<code>sControl</code> object. The main thread then calls:
<code>Dispatch sc = sCon.toDispatch();</code> to get a local Dispatch
proxy out of the DispatchProxy object.
<p>
At most <b>one(!)</b>
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.
<H3>Recommended Procedure</H3>
<ul>
<li>
It is recommended that you always allow JACOB to manage the main STA
rather than letting COM create one on its own or tag one of yours.
</li>
<li>
Declare an STA thread using ComThread.InitSTA()
if all your
method calls for that component are going to come from the same thread.
</li>
<li>
If you want an STA thread that allows other threads to call into it,
use the <code>com.jacob.com.STA</code> class as outlined above.
</li>
<li>
If you have a COM component that declares its ThreadingModel as
"Free" or "Both", then use the MTA.
</li>
<li>
In most cases, if you need to make method calls from multiple threads,
you can simply
use MTA threads, and allow COM to create the components in
the Main STA. You should only create your own STA's and DispatchProxy
if you understand COM well enough to know when the MTA solution
will fail or have other shortcomings.
<p>
There are 3 examples in the samples/test directory that demonstrate
these cases:
<p>
ScriptTest.java - creates an STA for the ScriptControl component and
runs all its method calls from that STA.
<p>
ScriptTest2.java - creates a separate STA thread, and makes
method calls into the component from another thread using DispatchProxy.
<p>
ScriptTest3.java - creates a separate MTA thread, and makes method
calls into the component from another MTA thread. This is simpler
than ScriptTest2 for most applications.
<p>
<h3>Default Threading Model</h3>
If you create a new thread, and don't call
<code>ComThread.InitSTA()</code> or <code>ComThread.InitMTA()</code>
on it, then the first time your java code creates a JacobObject, it
will try to register itself with the ROT, and when it sees that the
current thread is not initialized, it will initialize it as MTA.
This means that the code to do this is no longer inside the native
jni code - it is now in the <code>com.jacob.com.ROT</code> class.
For more details on the ROT, see the
<a href="JacobComLifetime.html">Object Lifetime</a> document.

File diff suppressed because it is too large Load Diff

View File

@@ -1,263 +0,0 @@
<HTML>
<BODY>
Jacob is a Java library that lets Java applications communicate with Microsoft Windows
DLLs or COM libraries. It does this through the use of a custom DLL that the Jacob
Java classes communicate with via JNI. The library and dll isolate the Java developer
from the underlying windows libraries so that the Java developer does not have to write
custom JNI code.
<p>
Jacob is not used for creating ActiveX plugins or other modules that
live inside of Microsoft Windows applications.
<hr>
<h2> The Jacob Packages </h2>
<p>
The JACOB jar contains two main packages: the <code>com.jacob.com.*</code>> package and
the <code>com.jacob.activeX</code> package. The <code>com.jacob.com.*</code> package contains classes
map very closely to the com dispatch model with the <code>com.jacob.com.Dispatch</code>
acting as the primary communication class. Dispatch operate as a function library with
a set of static methods that map very closely to the C++ Dispatch APIs provided
to the COM layer.
<p><code>com.jacob.activex.ActiveXComponent</code> can be used in place of Dispatch
to provide a more object like API.
The only exception to this guideline is that the <code>ActiveXComponent</code> class is always
used to make the initial connection to the target dll/COM component.
<hr>
<H2> Considerations when doing server side automation of office </h2>
<p>
Most office and many windows client type applications are not written to be used
in high volume or multi-threaded server environment. There is a
<a href="http://support.microsoft.com/kb/257757/">
support note </a>
on the Microsoft web site that discusses some of the issues.
<p>
<hr>
<H2> Determining the API of the target application </h2>
<p>
Section not yet written.
<p>
<hr>
<h2> The Jacob DLL </h2>
<p>
Jacob.jar relies on a DLL file that it loads off of the library path or classpath.
This means that you must either copy the appropriate jacob ddll into your path or
use VM options to add directory holding jacob dll to the path. Prior to 1.14M6,
the jacob DLL name was always "jacob.dll". This made it hard to verify jacob
was loading the correct dll when multiple copies of jacob were installed on a
single system. It also was confusing on 64 bit systems where the 32 bit and 64 bit
dlls have the same tames.
Starting in 1.14M6, Jacob's library
loader selects a dll with the appropriate name based on the jacob release and platform.
The dll naming convention is: <BR>
<code>jacob&lt;platform&gt;.&lt;version.&gt;.dll</code>
<p>
<h3>Classloader issues</h3>
The code is written so that the jacob.dll is only loaded one time per classloader.
This works fine in the standard application but can cause problems if jacob.jar
is loaded from more than one class loader. This can happen in the situation where multiple
jacob dependent web applications run in the same container like a web server or JWS runtime.
In the case of a web server, Jacob is normally put in the application specific WEB-INF/lib directory.
This is the "right" way to do it and works in most situations.
But, if Jacob is put in the WEB-INF/lib directory of each application's war file for more than
one application then a problem occurs.
In this situation, the web server uses a different classloader for each application.
This means that each application will attempt to load the jacob.dll and errors
are generated. The only way around this at this time (1.11) is to put the jacob.jar
in the common/lib because that classloader is inherited by all of the applications
so the DLLs will only get loaded once. This problem is described in SF 1645463 and
should be fixed in some future release, fix method and time not yet determined.
<p>
<hr>
<h2>Microsoft Visual C++ library dependencies.</h2>
<p>
Jacob 1.15 is build with VC++ 2005 statically linked into the DLL. This
removes the need for a separate msvcr80.dll installation.
</p>
<p>
Jacob 1.13 is built with VC++ 2005 that creates a dependency on msvcr80.dll.
Windows XP and later seem to already include the necessary components.
NT/2000 and Server/2003 require that you download the Visual C 2005 redistributable
package, vcredist_x86.exe from the Microsoft web site.
Microsoft has a download available that supplies the necessary components.
It is distributed as a redistributable package.
</p>
<p>
If you see the following message then you probably don't have the right C++ libraries.
</p>
<pre>
Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\apps\...\jacob.dll: This application has
failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem
</pre>
<pre>
<A href="http://www.microsoft.com/downloads/details.aspx?familyid=200B2FD9-AE1A-4A14-984D-389C36F85647&displaylang=en">
Visual C redistributable installer SP1</A>
</pre>
<p></p>
<hr>
<h2>Jacob Command Line Settings</h2>
This library supports several different command line options:
<table border=1>
<tr><td colspan=3>
<h3>dll path location and dll name customization</h3>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>java.library.path</h4>
</td><td>
Standard Java property used to add the location of the jacob dll to the JVM's library path.
(Added 1.11)
<p>
Example: <code>-Djava.library.path=d:/jacob/release/x86</code>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>jacob.dll.name</h4>
</td><td>
Override the standard DLL name with a custom one. This stops jacob from
using its 32bit/64bit detection and dll rendezvous logic.
Sometimes used when
Jacob is bundled with another application and the application wishes
to tie the jacob dll version number to the application version number.
(Added 1.14M7)
<p>
Example: <code>-Djacob.dll.name=MyFunkyDllName.dll</code>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>jacob.dll.name.x86 & jacob.dll.name.x64</h4>
</td><td>
Override the standard 32 bit DLL name with custom ones.
Sometimes used when
Jacob is bundled with another application and the application wishes
to tie the jacob dll version number to the application version number.
(Added 1.14M7)
<p>
Example to override 32 bit dll name: <code>-Djacob.dll.name.x86=MyFunkyDllName-32bit.dll</code>
</td></tr>
<tr><td colspan=3>
<h3>Memory Management</h3>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>com.jacob.autogc </h4>
</td><td>
Determines if automatic garbage collection is enabled. This is the
only way to free up objects created in event callbacks. Automatic garbage collection ,
based on Java gc rules, garbage collection can be enabled via the
<code>com.java.autogc</code> command line option.
<em>This feature was added in release 1.9 is not fully debugged. </em>
<p>
There are real reasons for managing the
lifetime of JacobObjects on a per thread basis.
Jacob normally manages the the com/Java object lifetime as described in the
<a href="JacobComLifetime.html">JacobComLifetime.html</a> document.
Some users have run into situations where they wish to try and let the Java
GC lifetime manage the lifetime of objects. This seems to usually be tied
to long running threads or to objects created as part of event callbacks.
Code was added to let users try and let the JVM manage the object life cycles
even though the <a href="JacobComLifetime.html">JacobComLifetime.html</a> document
says this is a bad idea. Added 1.9.
<p>
<p>
This value is cached at startup and cannot be changed on-the-fly via <code>System.setProperty();</code>
<p>
The default value is <em>false</em>
<p>
Example: <code>-Dcom.jacob.autogc=false</code>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>com.jacob.includeAllClassesInROT</h4>
</td><td>
Acts as master switch for and &ltclass_name&gt.PutInROT.
This property determines if the (experimental) PutInROT property is even
checked. It was added in version 1.15 because the property check in
PutInROT brok applets because they are not allowed to check system properties
at run time. com.jacob.includeAllClassesInROT is checked at class initialization
which is allowed.
<p>The default value of this flag is <i>true</i> which matches all behavior
prior to 1.13 and the default behavior for 1.13 on</p>
<p>Setting this flag to false causes Jacob to check the and &lt;class_name&gt;.PutInROT
property for every Jacob object that is created.</p>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>&ltclass_name&gt.PutInROT</h4>
</td><td>
Lets a program specify that instances of certain classes are to not be inserted
into the ROT. This experimental (1.13) feature provides a mechanism for freeing
VariantViaEvent objects that are created in Event threads. There is normally no
way to free those objects because the thread terminates outside of any normally MTA/STA
Startup/Teardown code. Each event occurs in a new thread and creates a new ROT entry
so they grow without bounds.
<p>
This option may cause VM crashes in certain situations where windows memory is freed
outside of the thread it was created in but empirical evidence shows there are
situations where this great reduces the long running memory footprint of applications
that process a lot of events. <em>This function is still experimental</em>.
The functionality was added 1.13. Some of this overlaps the experimental <code>com.jacob.autogc</code> introduced
in 1.9.
See the ROT.java test program for an example of the effects of this option.
<p>
This value is checked every time and can be changed on-the-fly via <code>System.setProperty();</code>
<p>
Example: <code>System.setProperty("com.jacob.com.VariantViaVariant.PutInROT","false");</code>
<BR>
Example: <code>-Dcom.jacob.com.VariantViaVariant.PutInROT=false</code>
</td></tr>
<tr><td colspan=3>
<h3>Debugging and Troubleshooting</h3>
</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>com.jacob.debug</h4>
</td><td>
Determines if debug output is enabled to standard out.
<p>
This value is cached at startup and cannot be changed on-the-fly via <code>System.setProperty();</code>
<p>
The default value is <strong>false</strong>
<p>
Example: <code>-Dcom.jacob.debug=false</code>
</td><tr>
<tr><td>&nbsp;&nbsp;&nbsp;</td><td valign="top">
<h4>-XCheck:jni</h4>
</td><td>
This turns on additional JVM checking for JNI issues. This is
not an actual JACOB system property but a property used by the JVM.
<p>
The default is "no additional checking"
Example: <code>-XCheck:jni</code>
</td></tr>
</table>
<p></p>
<hr>
<h2>Finding the DLL version using windows command line</h2>
The jacob.dll file includes the jacob release number in the version field.
Run the following from the command prompt <code>dumpbin /version jacob.dll</code> .
The dll version number is stored in the "image version" field of the
"OPTIONAL HEADER VALUES" section.
This information from <a href="http://msdn2.microsoft.com/en-gb/library/h88b7dc8(VS.71).aspx">
The Microsoft msdn web site</a>
<hr>
<h2>Unit Tests</h2>
Jacob must know the location of the DLL when running the unit tests in Eclipse.
The simplest way to do this is to add the dll path to the unit as a VM argument.
The argument should be specified based on where you installed the jacob source package.
If you have jacob unpacked in c:/dev/jacob and built using build.xml,
then the vm arguments would be:
<br><code>-Djava.library.path=c:/dev/jacob/release/x86</code> .
<p>
Last Modified 4/2008 1.15
</BODY>
</HTML>