merged R-1_9 release tag against the root-B-1_9

This commit is contained in:
clay_shooter
2005-02-26 21:32:27 +00:00
parent ebb1eddb69
commit bcf7bb0f85
132 changed files with 7134 additions and 4068 deletions

355
docs/EventCallbacks.htm Normal file
View File

@@ -0,0 +1,355 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 11">
<meta name=Originator content="Microsoft Word 11">
<link rel=File-List href="EventCallbacks_files/filelist.xml">
<title>Jacob can register Java classes for MS application events or callbacks</title>
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:RemovePersonalInformation/>
</o:OfficeDocumentSettings>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:DisplayBackgroundShape/>
<w:SpellingState>Clean</w:SpellingState>
<w:GrammarState>Clean</w:GrammarState>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SelectEntireFieldWithStartOrEnd/>
<w:UseWord2002TableStyleRules/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" LatentStyleCount="156">
</w:LatentStyles>
</xml><![endif]-->
<style>
<!--
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.MsoPlainText, li.MsoPlainText, div.MsoPlainText
{margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Courier New";
mso-fareast-font-family:"Times New Roman";}
span.SpellE
{mso-style-name:"";
mso-spl-e:yes;}
span.GramE
{mso-style-name:"";
mso-gram-e:yes;}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 65.95pt 1.0in 65.95pt;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
/* List Definitions */
@list l0
{mso-list-id:369961789;
mso-list-type:hybrid;
mso-list-template-ids:-80199436 -1920937264 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l0:level1
{mso-level-text:"%1\)";
mso-level-tab-stop:42.0pt;
mso-level-number-position:left;
margin-left:42.0pt;
text-indent:-24.0pt;}
@list l0:level2
{mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level3
{mso-level-tab-stop:1.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level4
{mso-level-tab-stop:2.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level5
{mso-level-tab-stop:2.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level6
{mso-level-tab-stop:3.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level7
{mso-level-tab-stop:3.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level8
{mso-level-tab-stop:4.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level9
{mso-level-tab-stop:4.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1
{mso-list-id:1316765558;
mso-list-type:hybrid;
mso-list-template-ids:860497186 -1920937264 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l1:level1
{mso-level-text:"%1\)";
mso-level-tab-stop:42.0pt;
mso-level-number-position:left;
margin-left:42.0pt;
text-indent:-24.0pt;}
@list l1:level2
{mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level3
{mso-level-tab-stop:1.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level4
{mso-level-tab-stop:2.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level5
{mso-level-tab-stop:2.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level6
{mso-level-tab-stop:3.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level7
{mso-level-tab-stop:3.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level8
{mso-level-tab-stop:4.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1:level9
{mso-level-tab-stop:4.5in;
mso-level-number-position:left;
text-indent:-.25in;}
ol
{margin-bottom:0in;}
ul
{margin-bottom:0in;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0in 5.4pt 0in 5.4pt;
mso-para-margin:0in;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]-->
</head>
<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<p class=MsoPlainText>Jacob can register Java classes for MS application events
or callbacks.<span style='mso-spacerun:yes'><EFBFBD> </span>The normal flow for this
is:</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>1)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>Application thread creates an instance of the
event handler and registers it with Jacob</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>2)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The application continues on doing other work.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>3)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>Some time later, the MS application takes some
action and initiates the event callback.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>4)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The Java VM receives the event and spins up a
new thread to handle it.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>5)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
in the <span class=SpellE>dll</span> is called by the VM.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>6)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
creates Variant objects to handle the parameters of the passed in event.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>7)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
uses reflection to map the event name to a method name with the exact same
name.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>8)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
sends the message to the registered event handler.</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
<p class=MsoPlainText>Swing developers should note that this message comes in
on a thread other than the event thread.<span style='mso-spacerun:yes'><EFBFBD>
</span>All objects receiving events that require user intervention or drawing
in the UI should use <span class=SpellE><span class=GramE>invokeLater</span></span><span
class=GramE>(</span>) to post requests for actions onto the event queue.<span
style='mso-spacerun:yes'><EFBFBD> </span>Failure to do so will insure random failures
in the GUI.</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
<p class=MsoPlainText>Java Web Start (JWS) and other launchers can have
additional issues related to the class loader.<span style='mso-spacerun:yes'><EFBFBD>
</span>The Jacob C++ library uses <span class=SpellE><span class=GramE>FindClass</span></span><span
class=GramE>(</span>) to find the Variant class when building the parameter
list.<span style='mso-spacerun:yes'><EFBFBD> </span><span class=SpellE><span
class=GramE>FindClass</span></span><span class=GramE>(</span>) uses the system
class loader which includes only the classes specified at run time or in the
CLASSPATH.<span style='mso-spacerun:yes'><EFBFBD> </span>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.<span
style='mso-spacerun:yes'><EFBFBD> </span>This means that the search for Variant will
fail usually with the silent and immediate termination of the Java application.<span
style='mso-spacerun:yes'><EFBFBD> </span>The thread <span class=SpellE>classloader</span>
probably can<61>t be used to try and find the class because this new thread does
not have a <span class=SpellE>classloader</span> associated with it other than
the system class loader.<span style='mso-spacerun:yes'><EFBFBD> </span>The end result
is that the Variant class needs to be located via other means and that the
thread <span class=SpellE>classloader</span> should be set to be the context
class loader of the event handler class.</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
<p class=MsoPlainText>The Jacob <span class=SpellE>EventProxy</span> class has
been modified (off of the 1.8 tree) so that it takes a two step approach to
towards fixing these problems.</p>
<p class=MsoPlainText><span style='mso-tab-count:2'><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </span></p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>1)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>The <span class=SpellE>EventProxy</span>
constructor now accepts an extra object, an instance of the Variant class.<span
style='mso-spacerun:yes'><EFBFBD> </span>This gives the <span class=SpellE>EventProxy</span>
a way to get to the Variant class and thus to its <span class=SpellE>classloader</span>.
All of the callers of the constructor have been modified to pass a Variant
object to the <span class=SpellE>EventProxy</span> without programmer
intervention.</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>2)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]><span class=SpellE>EventProxy</span> first
attempts to locate the Variant class using <span class=SpellE>FindClass</span>()</p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>3)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>Failing that, it looks to see if a variant
object had been passed in. If so, it calls <span class=GramE>class(</span>) and
goes from there.<span style='mso-spacerun:yes'><EFBFBD> </span></p>
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>4)<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]>If all that fails, it logs a message and then
fails in the spectacular fashion of the previous versions.</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
<p class=MsoPlainText>Developers can receive call back events in JWS other Java
launching programs without implementing any additional code.<span
style='mso-spacerun:yes'><EFBFBD> </span>They should be aware that their callback
methods may need to set the class <span class=GramE>loader.:</span></p>
<p class=MsoPlainText><span style='mso-tab-count:1'><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </span>Public xxx <span
class=SpellE><span class=GramE>someHandler</span></span><span class=GramE>(</span>Variant[]
<span class=SpellE>foo</span>){</p>
<p class=MsoPlainText><span style='mso-tab-count:2'><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </span><span
class=SpellE><span class=GramE>Thread.currentThread</span></span><span
class=GramE>(</span>).<span class=SpellE>setContextClassLoader</span>(</p>
<p class=MsoPlainText><span style='mso-tab-count:3'><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </span><span
class=SpellE><span class=GramE>this.getClass</span></span><span class=GramE>(</span>).<span
class=SpellE>getClassLoader</span>());</p>
<p class=MsoPlainText><span style='mso-tab-count:2'><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </span>// do
something</p>
<p class=MsoPlainText><span style='mso-tab-count:1'><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> </span>}</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
<p class=MsoPlainText>There may still be a dual event queue issue in JWS
applications that needs to be looked at.</p>
<p class=MsoPlainText><o:p>&nbsp;</o:p></p>
</div>
</body>
</html>

69
docs/HowToBuild.txt Normal file
View File

@@ -0,0 +1,69 @@
(2/2005)
To build and run:
Unpack the source archive or check the files out of CVS into d:\jacob
Install the following tools
Microsfot Visual Studio, a stripped down version is available from the MS web site.
Eclipse from www.eclipse.org.
Java jdk 1.4 (this was built using 1.4.2.06)
The following configuration was used by most of the development team:
JDK = d:\j2sdk1.4.2_06
DEST_DIR = d:\jacob
MSDEVDIR = d:\apps\\"Microsoft Visual Studio"\VC98
This project has been converted completely over to ANT. You can
run ANT from inside of eclipse or from the command line.
The ant process is driven off of a configuration file
compilation_tools.properties. Instructions on the information required
in that file are contained in build.xml in the root directory.
Ant, via build.xml will do the following with teh default target.
Build the Java code
Build the jni code
create the dll
create jar file
The package target creates the
javadoc and
zip files
ECLIPSE
Eclipse users will 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 com.jacob.com files located in the unittest directory while
the jacob files themselves are in com.jacob.com off the root directory.
(Eventually the the jacob files will be moved to src)
Eclipse automatically adds the whole project as a source directory
Remove the root of the project from the build path
Add folders samples, src and unittest to the build path
Exclude *.txt from each of the newly added folders.
A couple of the samples require a J2EE library in order to compile. This
means you'll have to add a J2EE jar file to your classpath. This
isn't a problem when using ANT because the Servlet examples are excluded
from the build.
--- old instructions for makefiles that no longer exist --
To build:
Run VCVARS32 to set up your MS Visual C++ environment
cd d:\jacob
nmake
(from dan)I developed this with the C++ compiler and ATL version
that ship with VC++ 6.0, so I'm not sure if different versions will
work.
This is currently designed to compile against JDK 1.4.2. The future
of the Microsoft SDK is in doubt so support may be discontinued
in the future.
The java code is in com\jacob\*.
The C++ code is in .\jni.

View File

@@ -0,0 +1,51 @@
<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.

410
docs/JacobThreading.html Normal file
View File

@@ -0,0 +1,410 @@
<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.

344
docs/WhatsNew.html Normal file
View File

@@ -0,0 +1,344 @@
<h1>What's New in JACOB 1.9</H1>
<ul>
<li>
<b>Event Callbacks</b>
<ul>
<li>Variant parameters can now be modified by the receiver to be passed
back to the COM caller </li>
<li>Callbacks can now be received when running in JWS other launchers where
JACOB.jar is not in the system classloader's path.</li>
</ul>
</li>
<li>
<b>Dispatch API Clarifications</B>
<ul>
<li>All static method's first parameters have been more strongly typed
to the Dispatch class, rather than Object. This may call for code
changes in the cases of code that just asigned Dispatch objects
to variables of type Object rather than Dispatch or one of its subclasses </li>
</ul>
</li>
<li>
<b>Dispatch subclasses are now supported with pointer modifying constructor</b>
<ul>
<li>Dispatch and ActiveXComponent now includes a constructor to be used by Dispatch subclasses
that swaps the pointers around. This eliminates the need for every Dispatch subclass
to have a constructor that swapped and nulled out the pointers to the COM layer.
All samples have updated to use the new api </li>
</ul>
</li>
<li>
<b>ActiveXComponent has been upgraded</b><ul>
<li>ActiveXComponent methods return ActiveXComponets </li>
<li>Methods have been added to the ActiveXComponents to retrieve
parameters as Dispatch objects or ActiveX components. The
Script Tests have been updated to show the same programs in Dispatch
format or ActiveXComponentFormat </li>
</ul>
</li>
<li>
<b>Memory Management</b>
<ul>
<li>Beta test option that lets an application use automatic object object
removal through the use of weak reference hash maps in the ROT class.&nbsp; The
default behavior of manual release via the COMThread class has been retained as
the default behavior.&nbsp; Developers can test automatic memory collection by
using the command line option <i>-Dcom.JACOB.autogc=true</i> </li>
</ul>
</li>
<li>
<b>JNI Changes</b>
<ul>
<li>Erroneous Array dimension checking fixed for certain boolean set and get functions
</li>
<li>Alternative method for finding Variant class for callbacks in JWS
or other application lanchers where the system classloader does not
know about JACOB classes. </li>
<li>Unicode is supported for putString and putStringRef</li>
<li>EventProxy zeros out the com object reference in the Variant objects
that are created by EventProxy so that they are not double released,
by both the Java VM and calling code from the COM side. The caller
is supposed to be responsible for releasing the memory it created.
This fix only applies to Variants created in callbacks. </li>
</ul>
</li>
<li>
<b>Logging Additions</b><ul>
<li>Debugging logging to standard out for JACOB can be turned on by using the
command line option <i>-Dcom.JACOB.debug=true</i></li>
</ul>
</li>
<li>
<b>Visual Studio</b><ul>
<li>The VisualStudio directory in the CVS repository will be removed in the next
release</li>
</ul>
</li>
<li>
<b>Documentation</b><ul>
<li>API documentation via Javadoc&nbsp; is now being generated for all classes.</li>
<li>The development team is looking for help in upgrading the quality of the
class documentation</li>
</ul>
</li>
<li>
<b>Build Changes</b>
<ul>
<li>A static method has been added to JacobObject that returns the build version</li>
<li>The project is now being built using ANT.&nbsp; Most of the developers are
running this from inside of Eclipse</li>
<li>All makefiles have been purged</li>
</ul>
<h2>Tracked Changes</h2>
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
<tr>
<td width="100%" colspan="2"><b>Bugs</b></td>
</tr>
<tr>
<td width="13%">1116101</td>
<td width="87%">jacob-msg 0284 : Access Violation while garbage collecting</td>
</tr>
<tr>
<td width="13%">1114159</td>
<td width="87%">Problem with COM Error Trapping in JACOB DLL</td>
</tr>
<tr>
<td width="13%">1113610</td>
<td width="87%">Bad error check in SafeArray.cpp</td>
</tr>
<tr>
<td width="13%">1066698</td>
<td width="87%">Minor Memory leak in Dispatch.cpp</td>
</tr>
<tr>
<td width="13%">1065533</td>
<td width="87%">Problem with unicode conversion</td>
</tr>
<tr>
<td width="13%">1053871</td>
<td width="87%">solution for memory leak in 1.7</td>
</tr>
<tr>
<td width="13%">1053870</td>
<td width="87%">JACOB0msg 2019 - Safe Array</td>
</tr>
<tr>
<td width="13%">1053866</td>
<td width="87%">getHResult only returns 80020009</td>
</tr>
<tr>
<td width="13%">960646</td>
<td width="87%">But in SafeArray:: getBoolean for 2D arrays</td>
</tr>
<tr>
<td width="13%">&nbsp;</td>
<td width="87%">&nbsp;</td>
</tr>
<tr>
<td width="100%" colspan="2"><b>Patches</b></td>
</tr>
<tr>
<td width="13%">1115187</td>
<td width="87%">EventCallbacks fail w/Variant ClassNotFoundException in JWS</td>
</tr>
<tr>
<td width="13%">1105915</td>
<td width="87%">Fix for event handling memory corruption</td>
</tr>
<tr>
<td width="13%">1090104</td>
<td width="87%">Weak Reference in teh ROT</td>
</tr>
<tr>
<td width="13%">1068544</td>
<td width="87%">in/out parameter support for event handlers</td>
</tr>
<tr>
<td width="13%">981540</td>
<td width="87%">jre 1.4.2 fix as patch</td>
</tr>
<tr>
<td width="13%">&nbsp;</td>
<td width="87%">&nbsp;</td>
</tr>
<tr>
<td width="100%" colspan="2"><b>Feature Requests</b></td>
</tr>
<tr>
<td width="13%">1049390</td>
<td width="87%">static Version information</td>
</tr>
<tr>
<td width="13%">1049224</td>
<td width="87%">Javadocs or at least script to generate it</td>
</tr>
<tr>
<td width="13%">1049158</td>
<td width="87%">API to get ProgId of ActiveXComponent</td>
</tr>
<tr>
<td width="13%">&nbsp;</td>
<td width="87%">&nbsp;</td>
</tr>
</table>
</li>
</ul>
<h1>What's New in JACOB 1.8</H1>
<ul>
<li>
<b>Move To SourceForge</b>
The project is not housed at
<a href="http://sourceforge.net/projects/jacob-project/">Sourceforge.net</a>.
</li>
<li>
<b>Licensing Change</b>
All limitations on commercial use of JACOB have been removed and it
is now being developed under a BSD license at
<a href="http://sourceforge.net/projects/jacob-project/">Sourceforge.net</a>.
</li>
<li>
<b>Compiled with Java 1.4.2</b>
Version 1.8 was compiled with JSEE 1.4.2 and fixes the compilation bug
that was remnant of compilation with JDK 1.1.
</li>
<li>
<b>Baseline For Change</b>
This version is the baseline for the first CVS checkin and we encourage
people to start contributing to the project with this version.
</li>
</ul>
<li>
<h1>What's New in JACOB 1.7</H1>
<ul>
<li>
<b>Explicit COM Threading Model Support:</b>
See a detailed discussion of
<a href="JacobThreading.html">COM Apartments in JACOB</a>
</li>
<li>
<b>New COM Object Lifetime model:</b>
See a detailed discussion of
<a href="JacobComLifetime.html">COM Object Lifetime in JACOB</a>.
</li>
<li>
<b>Improved Event Handling:</b>
Thanks to code contributed by
<a href="mailto:n.o.bouvin@daimi.au.dk">
Niels Olof Bouvin</a>
and <a href="mailto:jehoej@daimi.au.dk">Henning Jae</a> JACOB 1.7 can
read the type information of a Connection Point interface by looking
it up in the registry. This makes it possible to use events with IE as
well as office products.
</li>
<li>
<b>Improved Dispatch:</b>
Error messages from Invoke failures are now printed out as well as
allowing the passing in of arguments to a Get method.
</li>
<li>
<b>EnumVariant Implementation:</b>
Makes it easier to iterate over COM collections. Thanks to code
contributed by
<a href="mailto:Thomas.Hallgren@eoncompany.com">Thomas Hallgren</a>.
</li>
<li>
<b>SafeArray leaks:</b>
SafeArrays were not being properly freed prior to version 1.7, many
other memory leaks were fixed as well.
</li>
<li>
<b>Visual Studio Project:</b>
For those who want to debug: vstudio/JACOB. At the moment all the
native code is replicated there from the jni directory...
</li>
</ul>
<H1>Related Links</H1>
<ul>
<li>
The JACOB mailing list is hosted at yahoo groups:
<a href="http://groups.yahoo.com/group/jacob-project">
http://groups.yahoo.com/group/JACOB-project</a>.
<b>This is the preferred way to get support for JACOB</b>. It also
includes an extensive archive. If you are doing any development with
JACOB, please join the list.
<li>
Massimiliano Bigatti has developed
<a href="http://www.bigatti.it/projects/jacobgen/">
JACOBgen - a generator that automatically creates JACOB code from
Type Libraries</a>
</li>
<li>
Steven Lewis is developing a version of Java2Com that supports JACOB
code generation. See:
<a href="http://www.lordjoe.com/Java2Com/index.html">
http://www.lordjoe.com/Java2Com/index.html</a>.
<li>
To find documentation on the com.ms.com package, go to:
<a href="http://www.microsoft.com/java/download/dl_sdk40.htm">
http://www.microsoft.com/java/download/dl_sdk40.htm</a>
and at the bottom of the page is a link that says:
Microsoft SDK for Java 4.0 Documentation Only. You should download
that file and install it. Then, view sdkdocs.chm and look for
"Microsoft Packages Reference". Hopefully, the next release of
JACOB will include full javadoc (volunteers?)...</li>

3
docs/todo.txt Normal file
View File

@@ -0,0 +1,3 @@
1. Make everything check the current thread's mta-ness
2. Write more documentation
3. Get someone to help write the Javadoc