Merge branch 'Branch_T-1_15-M3'

Conflicts:
	README.txt
	build.xml
	docs/BuildingJacobFromSource.html
	docs/ReleaseNotes.html
	docs/UsingJacob.html
This commit is contained in:
2014-12-07 09:50:48 +00:00
34 changed files with 8481 additions and 1053 deletions

View File

@@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

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.

View File

@@ -0,0 +1,2 @@
*.class

View File

@@ -0,0 +1,579 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.activeX;
import com.jacob.com.Dispatch;
import com.jacob.com.JacobObject;
import com.jacob.com.Variant;
/**
* This class provides a higher level, more object like, wrapper for top of the
* Dispatch object. The Dispatch class's method essentially directly map to
* Microsoft C API including the first parameter that is almost always the
* target of the message. ActiveXComponent assumes the target of every message
* is the MS COM object behind the ActiveXComponent. This removes the need to
* pass the Dispatch object into every method.
* <p>
* It is really up to the developer as to whether they want to use the Dispatch
* interface or the ActiveXComponent interface.
* <p>
* This class simulates com.ms.activeX.ActiveXComponent only in the sense that
* it is used for creating Dispatch objects
*/
public class ActiveXComponent extends Dispatch {
/**
* Normally used to create a new connection to a microsoft application. The
* passed in parameter is the name of the program as registered in the
* registry. It can also be the object name.
* <p>
* This constructor causes a new Windows object of the requested type to be
* created. The windows CoCreate() function gets called to create the
* underlying windows object.
*
* <pre>
* new ActiveXComponent(&quot;ScriptControl&quot;);
* </pre>
*
* @param programId
*/
public ActiveXComponent(String programId) {
super(programId);
}
/**
* Creates an active X component that is built on top of the COM pointers
* held in the passed in dispatch. This widens the Dispatch object to pick
* up the ActiveXComponent API
*
* @param dispatchToBeWrapped
*/
public ActiveXComponent(Dispatch dispatchToBeWrapped) {
super(dispatchToBeWrapped);
}
/**
* only used by the factories
*
*/
private ActiveXComponent() {
super();
}
/**
* Probably was a cover for something else in the past. Should be
* deprecated.
*
* @return Now it actually returns this exact same object.
*/
public Dispatch getObject() {
return this;
}
/**
* Most code should use the standard ActiveXComponent(String) contructor and
* not this factory method. This method exists for applications that need
* special behavior. <B>Experimental in release 1.9.2.</B>
* <p>
* Factory that returns a Dispatch object wrapped around the result of a
* CoCreate() call. This differs from the standard constructor in that it
* throws no exceptions and returns null on failure.
* <p>
* This will fail for any prog id with a ":" in it.
*
* @param pRequestedProgramId
* @return Dispatch pointer to the COM object or null if couldn't create
*/
public static ActiveXComponent createNewInstance(String pRequestedProgramId) {
ActiveXComponent mCreatedDispatch = null;
try {
mCreatedDispatch = new ActiveXComponent();
mCreatedDispatch.coCreateInstance(pRequestedProgramId);
} catch (Exception e) {
mCreatedDispatch = null;
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("Unable to co-create instance of "
+ pRequestedProgramId);
}
}
return mCreatedDispatch;
}
/**
* Most code should use the standard ActiveXComponent(String) constructor and
* not this factory method. This method exists for applications that need
* special behavior. <B>Experimental in release 1.9.2.</B>
* <p>
* Factory that returns a Dispatch wrapped around the result of a
* getActiveObject() call. This differs from the standard constructor in
* that it throws no exceptions and returns null on failure.
* <p>
* This will fail for any prog id with a ":" in it
*
* @param pRequestedProgramId
* @return Dispatch pointer to a COM object or null if wasn't already
* running
*/
public static ActiveXComponent connectToActiveInstance(
String pRequestedProgramId) {
ActiveXComponent mCreatedDispatch = null;
try {
mCreatedDispatch = new ActiveXComponent();
mCreatedDispatch.getActiveInstance(pRequestedProgramId);
} catch (Exception e) {
mCreatedDispatch = null;
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("Unable to attach to running instance of "
+ pRequestedProgramId);
}
}
return mCreatedDispatch;
}
/**
* @see com.jacob.com.Dispatch#finalize()
*/
protected void finalize() {
super.finalize();
}
/*
* ============================================================
*
* start of instance based calls to the COM layer
* ===========================================================
*/
/**
* retrieves a property and returns it as a Variant
*
* @param propertyName
* @return variant value of property
*/
public Variant getProperty(String propertyName) {
return Dispatch.get(this, propertyName);
}
/**
* retrieves a property and returns it as an ActiveX component
*
* @param propertyName
* @return Dispatch representing the object under the property name
*/
public ActiveXComponent getPropertyAsComponent(String propertyName) {
return new ActiveXComponent(Dispatch.get(this, propertyName)
.toDispatch());
}
/**
* retrieves a property and returns it as a Boolean
*
* @param propertyName
* property we are looking up
* @return boolean value of property
*/
public boolean getPropertyAsBoolean(String propertyName) {
return Dispatch.get(this, propertyName).getBoolean();
}
/**
* retrieves a property and returns it as a byte
*
* @param propertyName
* property we are looking up
* @return byte value of property
*/
public byte getPropertyAsByte(String propertyName) {
return Dispatch.get(this, propertyName).getByte();
}
/**
* retrieves a property and returns it as a String
*
* @param propertyName
* @return String value of property
*/
public String getPropertyAsString(String propertyName) {
return Dispatch.get(this, propertyName).getString();
}
/**
* retrieves a property and returns it as a int
*
* @param propertyName
* @return the property value as an int
*/
public int getPropertyAsInt(String propertyName) {
return Dispatch.get(this, propertyName).getInt();
}
/**
* sets a property on this object
*
* @param propertyName
* property name
* @param arg
* variant value to be set
*/
public void setProperty(String propertyName, Variant arg) {
Dispatch.put(this, propertyName, arg);
}
/**
* sets a property on this object
*
* @param propertyName
* property name
* @param arg
* variant value to be set
*/
public void setProperty(String propertyName, Dispatch arg) {
Dispatch.put(this, propertyName, arg);
}
/**
* sets a property to be the value of the string
*
* @param propertyName
* @param propertyValue
*/
public void setProperty(String propertyName, String propertyValue) {
this.setProperty(propertyName, new Variant(propertyValue));
}
/**
* sets a property as a boolean value
*
* @param propertyName
* @param propValue
* the boolean value we want the prop set to
*/
public void setProperty(String propertyName, boolean propValue) {
this.setProperty(propertyName, new Variant(propValue));
}
/**
* sets a property as a boolean value
*
* @param propertyName
* @param propValue
* the boolean value we want the prop set to
*/
public void setProperty(String propertyName, byte propValue) {
this.setProperty(propertyName, new Variant(propValue));
}
/**
* sets the property as an int value
*
* @param propertyName
* @param propValue
* the int value we want the prop to be set to.
*/
public void setProperty(String propertyName, int propValue) {
this.setProperty(propertyName, new Variant(propValue));
}
/*-------------------------------------------------------
* Listener logging helpers
*-------------------------------------------------------
*/
/**
* This boolean determines if callback events should be logged
*/
public static boolean shouldLogEvents = false;
/**
* used by the doc and application listeners to get intelligent logging
*
* @param description
* event description
* @param args
* args passed in (variants)
*
*/
public void logCallbackEvent(String description, Variant[] args) {
String argString = "";
if (args != null && ActiveXComponent.shouldLogEvents) {
if (args.length > 0) {
argString += " args: ";
}
for (int i = 0; i < args.length; i++) {
short argType = args[i].getvt();
argString += ",[" + i + "]";
// break out the byref bits if they are on this
if ((argType & Variant.VariantByref) == Variant.VariantByref) {
// show the type and the fact that its byref
argString += "("
+ (args[i].getvt() & ~Variant.VariantByref) + "/"
+ Variant.VariantByref + ")";
} else {
// show the type
argString += "(" + argType + ")";
}
argString += "=";
if (argType == Variant.VariantDispatch) {
Dispatch foo = (args[i].getDispatch());
argString += foo;
} else if ((argType & Variant.VariantBoolean) == Variant.VariantBoolean) {
// do the boolean thing
if ((argType & Variant.VariantByref) == Variant.VariantByref) {
// boolean by ref
argString += args[i].getBooleanRef();
} else {
// boolean by value
argString += args[i].getBoolean();
}
} else if ((argType & Variant.VariantString) == Variant.VariantString) {
// do the string thing
if ((argType & Variant.VariantByref) == Variant.VariantByref) {
// string by ref
argString += args[i].getStringRef();
} else {
// string by value
argString += args[i].getString();
}
} else {
argString += args[i].toString();
}
}
System.out.println(description + argString);
}
}
/*
* ==============================================================
*
* covers for dispatch call methods
* =============================================================
*/
/**
* makes a dispatch call for the passed in action and no parameter
*
* @param callAction
* @return ActiveXComponent representing the results of the call
*/
public ActiveXComponent invokeGetComponent(String callAction) {
return new ActiveXComponent(invoke(callAction).toDispatch());
}
/**
* makes a dispatch call for the passed in action and single parameter
*
* @param callAction
* @param parameter
* @return ActiveXComponent representing the results of the call
*/
public ActiveXComponent invokeGetComponent(String callAction,
Variant parameter) {
return new ActiveXComponent(invoke(callAction, parameter).toDispatch());
}
/**
* makes a dispatch call for the passed in action and single parameter
*
* @param callAction
* @param parameter1
* @param parameter2
* @return ActiveXComponent representing the results of the call
*/
public ActiveXComponent invokeGetComponent(String callAction,
Variant parameter1, Variant parameter2) {
return new ActiveXComponent(invoke(callAction, parameter1, parameter2)
.toDispatch());
}
/**
* makes a dispatch call for the passed in action and single parameter
*
* @param callAction
* @param parameter1
* @param parameter2
* @param parameter3
* @return ActiveXComponent representing the results of the call
*/
public ActiveXComponent invokeGetComponent(String callAction,
Variant parameter1, Variant parameter2, Variant parameter3) {
return new ActiveXComponent(invoke(callAction, parameter1, parameter2,
parameter3).toDispatch());
}
/**
* makes a dispatch call for the passed in action and single parameter
*
* @param callAction
* @param parameter1
* @param parameter2
* @param parameter3
* @param parameter4
* @return ActiveXComponent representing the results of the call
*/
public ActiveXComponent invokeGetComponent(String callAction,
Variant parameter1, Variant parameter2, Variant parameter3,
Variant parameter4) {
return new ActiveXComponent(invoke(callAction, parameter1, parameter2,
parameter3, parameter4).toDispatch());
}
/**
* invokes a single parameter call on this dispatch that returns no value
*
* @param actionCommand
* @param parameter
* @return a Variant but that may be null for some calls
*/
public Variant invoke(String actionCommand, String parameter) {
return Dispatch.call(this, actionCommand, parameter);
}
/**
* makes a dispatch call to the passed in action with a single boolean
* parameter
*
* @param actionCommand
* @param parameter
* @return Variant result
*/
public Variant invoke(String actionCommand, boolean parameter) {
return Dispatch.call(this, actionCommand, new Variant(parameter));
}
/**
* makes a dispatch call to the passed in action with a single int parameter
*
* @param actionCommand
* @param parameter
* @return Variant result of the invoke (Dispatch.call)
*/
public Variant invoke(String actionCommand, int parameter) {
return Dispatch.call(this, actionCommand, new Variant(parameter));
}
/**
* makes a dispatch call to the passed in action with a string and integer
* parameter (this was put in for some application)
*
* @param actionCommand
* @param parameter1
* @param parameter2
* @return Variant result
*/
public Variant invoke(String actionCommand, String parameter1,
int parameter2) {
return Dispatch.call(this, actionCommand, parameter1, new Variant(
parameter2));
}
/**
* makes a dispatch call to the passed in action with two integer parameters
* (this was put in for some application)
*
* @param actionCommand
* @param parameter1
* @param parameter2
* @return a Variant but that may be null for some calls
*/
public Variant invoke(String actionCommand, int parameter1, int parameter2) {
return Dispatch.call(this, actionCommand, new Variant(parameter1),
new Variant(parameter2));
}
/**
* makes a dispatch call for the passed in action and single parameter
*
* @param callAction
* @param parameter
* @return a Variant but that may be null for some calls
*/
public Variant invoke(String callAction, Variant parameter) {
return Dispatch.call(this, callAction, parameter);
}
/**
* makes a dispatch call for the passed in action and two parameter
*
* @param callAction
* @param parameter1
* @param parameter2
* @return a Variant but that may be null for some calls
*/
public Variant invoke(String callAction, Variant parameter1,
Variant parameter2) {
return Dispatch.call(this, callAction, parameter1, parameter2);
}
/**
* makes a dispatch call for the passed in action and two parameter
*
* @param callAction
* @param parameter1
* @param parameter2
* @param parameter3
* @return Variant result data
*/
public Variant invoke(String callAction, Variant parameter1,
Variant parameter2, Variant parameter3) {
return Dispatch.call(this, callAction, parameter1, parameter2,
parameter3);
}
/**
* calls call() with 4 variant parameters
*
* @param callAction
* @param parameter1
* @param parameter2
* @param parameter3
* @param parameter4
* @return Variant result data
*/
public Variant invoke(String callAction, Variant parameter1,
Variant parameter2, Variant parameter3, Variant parameter4) {
return Dispatch.call(this, callAction, parameter1, parameter2,
parameter3, parameter4);
}
/**
* makes a dispatch call for the passed in action and no parameter
*
* @param callAction
* @return a Variant but that may be null for some calls
*/
public Variant invoke(String callAction) {
return Dispatch.call(this, callAction);
}
/**
* This is really a cover for call(String,Variant[]) that should be
* eliminated call with a variable number of args mainly used for quit.
*
* @param name
* @param args
* @return Variant returned by the invoke (Dispatch.callN)
*/
public Variant invoke(String name, Variant[] args) {
return Dispatch.callN(this, name, args);
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.activeX;
import com.jacob.com.Dispatch;
import com.jacob.com.DispatchEvents;
import com.jacob.com.InvocationProxy;
/**
* RELEASE 1.12 EXPERIMENTAL.
* <p>
* Use this exactly like the DispatchEvents class. This class plugs in an
* ActiveXInvocationProxy instead of an InvocationProxy. It is the
* ActiveXInvocationProxy that implements the reflection calls and invoke the
* found java event callbacks. See ActiveXInvocationProxy for details.
*
*
*/
public class ActiveXDispatchEvents extends DispatchEvents {
/**
* This is the most commonly used constructor.
* <p>
* Creates the event callback linkage between the the MS program represented
* by the Dispatch object and the Java object that will receive the
* callback.
*
* @param sourceOfEvent
* Dispatch object who's MS app will generate callbacks
* @param eventSink
* Java object that wants to receive the events
*/
public ActiveXDispatchEvents(Dispatch sourceOfEvent, Object eventSink) {
super(sourceOfEvent, eventSink, null);
}
/**
* None of the samples use this constructor.
* <p>
* Creates the event callback linkage between the the MS program represented
* by the Dispatch object and the Java object that will receive the
* callback.
*
* @param sourceOfEvent
* Dispatch object who's MS app will generate callbacks
* @param eventSink
* Java object that wants to receive the events
* @param progId
* ???
*/
public ActiveXDispatchEvents(Dispatch sourceOfEvent, Object eventSink,
String progId) {
super(sourceOfEvent, eventSink, progId, null);
}
/**
* Creates the event callback linkage between the the MS program represented
* by the Dispatch object and the Java object that will receive the
* callback.
*
* <pre>
* &gt;ActiveXDispatchEvents de =
* new ActiveXDispatchEvents(someDispatch,someEventHAndler,
* &quot;Excel.Application&quot;,
* &quot;C:\\Program Files\\Microsoft Office\\OFFICE11\\EXCEL.EXE&quot;);
*
* @param sourceOfEvent Dispatch object who's MS app will generate callbacks
* @param eventSink Java object that wants to receive the events
* @param progId , mandatory if the typelib is specified
* @param typeLib The location of the typelib to use
*
*/
public ActiveXDispatchEvents(Dispatch sourceOfEvent, Object eventSink,
String progId, String typeLib) {
super(sourceOfEvent, eventSink, progId, typeLib);
}
/*
* (non-Javadoc)
*
* @see com.jacob.com.DispatchEvents#getInvocationProxy(java.lang.Object)
*/
protected InvocationProxy getInvocationProxy(Object pTargetObject) {
InvocationProxy newProxy = new ActiveXInvocationProxy();
newProxy.setTarget(pTargetObject);
return newProxy;
}
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.activeX;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.jacob.com.InvocationProxy;
import com.jacob.com.NotImplementedException;
import com.jacob.com.Variant;
/**
* RELEASE 1.12 EXPERIMENTAL.
* <p>
* This class that lets event handlers receive events with all java objects as
* parameters. The standard Jacob event methods all accept an array of Variant
* objects. When using this class, you can set up your event methods as regular
* java methods with the correct number of parameters of the correct java type.
* This does NOT work for any event that wishes to accept a call back and modify
* the calling parameters to tell windows what to do. An example is when an
* event lets the receiver cancel the action by setting a boolean flag to false.
* The java objects cannot be modified and their values will not be passed back
* into the originating Variants even if they could be modified.
* <p>
* This class acts as a proxy between the windows event callback mechanism and
* the Java classes that are looking for events. It assumes that all of the Java
* classes that are looking for events implement methods with the same names as
* the windows events and that the implemented methods native java objects of
* the type and order that match the windows documentation. The methods can
* return void or a Variant that will be returned to the calling layer. All
* Event methods that will be recognized by InvocationProxyAllEvents have the
* signature
*
* <code> void eventMethodName(Object,Object...)</code> or
* <code> Object eventMethodName(Object,Object...)</code>
*/
public class ActiveXInvocationProxy extends InvocationProxy {
/*
* (non-Javadoc)
*
* @see com.jacob.com.InvocationProxy#invoke(java.lang.String,
* com.jacob.com.Variant[])
*/
@SuppressWarnings("unchecked")
public Variant invoke(String methodName, Variant targetParameters[]) {
Variant mVariantToBeReturned = null;
if (mTargetObject == null) {
// structured programming guidlines say this return should not be up
// here
return null;
}
Class targetClass = mTargetObject.getClass();
if (methodName == null) {
throw new IllegalArgumentException(
"InvocationProxy: missing method name");
}
if (targetParameters == null) {
throw new IllegalArgumentException(
"InvocationProxy: missing Variant parameters");
}
try {
Method targetMethod;
Object parametersAsJavaObjects[] = getParametersAsJavaObjects(targetParameters);
Class parametersAsJavaClasses[] = getParametersAsJavaClasses(parametersAsJavaObjects);
targetMethod = targetClass.getMethod(methodName,
parametersAsJavaClasses);
if (targetMethod != null) {
// protected classes can't be invoked against even if they
// let you grab the method. you could do
// targetMethod.setAccessible(true);
// but that should be stopped by the security manager
Object mReturnedByInvocation = null;
mReturnedByInvocation = targetMethod.invoke(mTargetObject,
parametersAsJavaObjects);
if (mReturnedByInvocation == null) {
mVariantToBeReturned = null;
} else if (!(mReturnedByInvocation instanceof Variant)) {
mVariantToBeReturned = new Variant(mReturnedByInvocation);
} else {
mVariantToBeReturned = (Variant) mReturnedByInvocation;
}
}
} catch (SecurityException e) {
// what causes this exception?
e.printStackTrace();
} catch (NoSuchMethodException e) {
// this happens whenever the listener doesn't implement all the
// methods
} catch (IllegalArgumentException e) {
// we can throw these inside the catch block so need to re-throw it
Exception oneWeShouldToss = new IllegalArgumentException(
"Unable to map parameters for method " + methodName + ": "
+ e.toString());
oneWeShouldToss.printStackTrace();
} catch (IllegalAccessException e) {
// can't access the method on the target instance for some reason
e.printStackTrace();
} catch (InvocationTargetException e) {
// invocation of target method failed
e.printStackTrace();
}
return mVariantToBeReturned;
}
/**
* creates a method signature compatible array of classes from an array of
* parameters
*
* @param parametersAsJavaObjects
* @return
*/
@SuppressWarnings("unchecked")
private Class[] getParametersAsJavaClasses(Object[] parametersAsJavaObjects) {
if (parametersAsJavaObjects == null) {
throw new IllegalArgumentException(
"This only works with an array of parameters");
}
int numParameters = parametersAsJavaObjects.length;
Class parametersAsJavaClasses[] = new Class[numParameters];
for (int parameterIndex = 0; parameterIndex < numParameters; parameterIndex++) {
Object oneParameterObject = parametersAsJavaObjects[parameterIndex];
if (oneParameterObject == null) {
parametersAsJavaClasses[parameterIndex] = null;
} else {
Class oneParameterClass = oneParameterObject.getClass();
parametersAsJavaClasses[parameterIndex] = oneParameterClass;
}
}
return parametersAsJavaClasses;
}
/**
* converts an array of Variants to their associated Java types
*
* @param targetParameters
* @return
*/
private Object[] getParametersAsJavaObjects(Variant[] targetParameters) {
if (targetParameters == null) {
throw new IllegalArgumentException(
"This only works with an array of parameters");
}
int numParameters = targetParameters.length;
Object parametersAsJavaObjects[] = new Object[numParameters];
for (int parameterIndex = 0; parameterIndex < numParameters; parameterIndex++) {
Variant oneParameterObject = targetParameters[parameterIndex];
if (oneParameterObject == null) {
parametersAsJavaObjects[parameterIndex] = null;
} else {
try {
parametersAsJavaObjects[parameterIndex] = oneParameterObject
.toJavaObject();
} catch (NotImplementedException nie) {
throw new IllegalArgumentException(
"Can't convert parameter " + parameterIndex
+ " type " + oneParameterObject.getvt()
+ " to java object: " + nie.getMessage());
}
}
}
return parametersAsJavaObjects;
}
}

View File

@@ -0,0 +1,2 @@
*.class

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* Standard exception thrown by com jni code when there is a problem
*/
public abstract class ComException extends JacobException {
/**
* COM code initializes this filed with an appropriate return code that was
* returned by the underlying com code
*/
protected int hr;
/**
* No documentation is available at this time. Someone should document this
* field
*/
protected int m_helpContext;
/**
* No documentation is available at this time. Someone should document this
* field
*/
protected String m_helpFile;
/**
* No documentation is available at this time. Someone should document this
* field
*/
protected String m_source;
/**
* constructor
*
*/
public ComException() {
super();
}
/**
* constructor with error code?
*
* @param newHr ??
*/
public ComException(int newHr) {
super();
this.hr = newHr;
}
/**
* @param newHr
* @param description
*/
public ComException(int newHr, String description) {
super(description);
this.hr = newHr;
}
/**
* @param newHr
* @param source
* @param helpFile
* @param helpContext
*/
public ComException(int newHr, String source, String helpFile,
int helpContext) {
super();
this.hr = newHr;
m_source = source;
m_helpFile = helpFile;
m_helpContext = helpContext;
}
/**
* @param newHr
* @param description
* @param source
* @param helpFile
* @param helpContext
*/
public ComException(int newHr, String description, String source,
String helpFile, int helpContext) {
super(description);
this.hr = newHr;
m_source = source;
m_helpFile = helpFile;
m_helpContext = helpContext;
}
/**
* @param description
*/
public ComException(String description) {
super(description);
}
/**
* @return int representation of the help context
*/
// Methods
public int getHelpContext() {
return m_helpContext;
}
/**
* @return String ??? help file
*/
public String getHelpFile() {
return m_helpFile;
}
/**
* @return int hr result ??
*/
public int getHResult() {
return hr;
}
/**
* @return String source ??
*/
public String getSource() {
return m_source;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* COM Fail Exception class raised when there is a problem
*/
public class ComFailException extends ComException {
/**
* eclipse generated to get rid of a wanring
*/
private static final long serialVersionUID = -266047261992987700L;
/**
* Constructor
*
* @param hrNew
*/
public ComFailException(int hrNew) {
super(hrNew);
}
/**
* Constructor
*
* @param hrNew
* @param message
*/
public ComFailException(int hrNew, String message) {
super(hrNew, message);
}
/**
* @param hrNew
* @param source
* @param helpFile
* @param helpContext
*/
public ComFailException(int hrNew, String source, String helpFile,
int helpContext) {
super(hrNew, source, helpFile, helpContext);
}
/**
* Constructor
*
* @param hrNew
* @param description
* @param source
* @param helpFile
* @param helpContext
*/
public ComFailException(int hrNew, String description, String source,
String helpFile, int helpContext) {
super(hrNew, description, source, helpFile, helpContext);
}
/**
* No argument Constructor
*/
public ComFailException() {
super();
}
/**
* @param message
*/
public ComFailException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* Represents a COM level thread This is an abstract class because all the
* methods are static and no instances are ever created.
*/
public abstract class ComThread {
private static final int MTA = 0x0;
private static final int STA = 0x2;
/**
* Comment for <code>haveSTA</code>
*/
public static boolean haveSTA = false;
/**
* Comment for <code>mainSTA</code>
*/
public static MainSTA mainSTA = null;
/**
* Initialize the current java thread to be part of the Multi-threaded COM
* Apartment
*/
public static synchronized void InitMTA() {
InitMTA(false);
}
/**
* Initialize the current java thread to be an STA
*/
public static synchronized void InitSTA() {
InitSTA(false);
}
/**
* Initialize the current java thread to be part of the Multi-threaded COM
* Apartment, if createMainSTA is true, create a separate MainSTA thread
* that will house all Apartment Threaded components
*
* @param createMainSTA
*/
public static synchronized void InitMTA(boolean createMainSTA) {
Init(createMainSTA, MTA);
}
/**
* Initialize the current java thread to be an STA COM Apartment, if
* createMainSTA is true, create a separate MainSTA thread that will house
* all Apartment Threaded components
*
* @param createMainSTA
*/
public static synchronized void InitSTA(boolean createMainSTA) {
Init(createMainSTA, STA);
}
/**
*
*/
public static synchronized void startMainSTA() {
mainSTA = new MainSTA();
haveSTA = true;
}
/**
*
*/
public static synchronized void quitMainSTA() {
if (mainSTA != null)
mainSTA.quit();
}
/**
* Initialize the current java thread to be part of the MTA/STA COM
* Apartment
*
* @param createMainSTA
* @param mode
*/
public static synchronized void Init(boolean createMainSTA, int mode) {
if (createMainSTA && !haveSTA) {
// if the current thread is going to be in the MTA and there
// is no STA thread yet, then create a main STA thread
// to avoid COM creating its own
startMainSTA();
}
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ComThread: before Init: " + mode);
}
doCoInitialize(mode);
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ComThread: after Init: " + mode);
}
ROT.addThread();
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ComThread: after ROT.addThread: " + mode);
}
}
/**
* Call CoUninitialize to release this java thread from COM
*/
public static synchronized void Release() {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ComThread: before clearObjects");
}
ROT.clearObjects();
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ComThread: before UnInit");
}
doCoUninitialize();
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ComThread: after UnInit");
}
}
/**
* @deprecated the java model leave the responsibility of clearing up
* objects to the Garbage Collector. Our programming model
* should not require that the user specifically remove object
* from the thread.
*
* This will remove an object from the ROT
* @param o
*/
@Deprecated
public static synchronized void RemoveObject(JacobObject o) {
ROT.removeObject(o);
}
/**
* @param threadModel
*/
public static native void doCoInitialize(int threadModel);
/**
*
*/
public static native void doCoUninitialize();
/**
* load the Jacob DLL. We do this in case COMThread is called before any
* other reference to one of the JacboObject subclasses is made.
*/
static {
LibraryLoader.loadJacobLibrary();
}
}

View File

@@ -0,0 +1,91 @@
package com.jacob.com;
/**
* Most COM bridges use java.lang.Long as their Java data type for COM Currency
* data. This is because COM currency is a 64 bit number where the last 4 digits
* represent the milli-cents. We wanted to support 64 bit Long values for x64
* platforms so that meant we wanted to map Java.LONG to COM.LONG even though it
* only works for 64 bit platforms. The end result was we needed a new
* representation for Money so we have this.
* <p>
* In the future, this should convert to and from BigDecimal or Double
*/
public class Currency {
Long embeddedValue = null;
/**
* constructor that takes a long already in COM representation
*
* @param newValue
*/
public Currency(long newValue) {
embeddedValue = new Long(newValue);
}
/**
* constructor that takes a String already in COM representation
*
* @param newValue
*/
public Currency(String newValue) {
embeddedValue = new Long(newValue);
}
/**
*
* @return the currency as a primitive long
*/
public long longValue() {
return embeddedValue.longValue();
}
/**
* getter to the inner storage so that cmpareTo can work
*
* @return the embedded long value
*/
protected Long getLongValue() {
return embeddedValue;
}
/**
* compares the values of two currencies
*
* @param anotherCurrency
* @return the usual compareTo results
*/
public int compareTo(Currency anotherCurrency) {
return embeddedValue.compareTo(anotherCurrency.getLongValue());
}
/**
* standard comparison
*
* @param o
* must be Currency or Long
* @return the usual compareTo results
*/
public int compareTo(Object o) {
if (o instanceof Currency) {
return compareTo((Currency) o);
} else if (o instanceof Long) {
return embeddedValue.compareTo((Long) o);
} else
throw new IllegalArgumentException(
"Can only compare to Long and Currency not "
+ o.getClass().getName());
}
/**
* {@inheritDoc}
*/
public boolean equals(Object o) {
if (o == null) {
return false;
} else if (compareTo(o) == 0) {
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
import java.util.Calendar;
import java.util.Date;
/**
* java / windows date conversion utilities
*
* @author joe
*
*/
public class DateUtilities {
/**
* converts a windows time to a Java Date Object
*
* @param comTime
* @return Date object representing the windows time as specified in comTime
*/
static public Date convertWindowsTimeToDate(double comTime) {
return new Date(convertWindowsTimeToMilliseconds(comTime));
}
/**
* Convert a COM time from functions Date(), Time(), Now() to a Java time
* (milliseconds). Visual Basic time values are based to 30.12.1899, Java
* time values are based to 1.1.1970 (= 0 milliseconds). The difference is
* added to the Visual Basic value to get the corresponding Java value. The
* Visual Basic double value reads: <day count delta since 30.12.1899>.<1
* day percentage fraction>, e.g. "38100.6453" means: 38100 days since
* 30.12.1899 plus (24 hours * 0.6453). Example usage:
* <code>Date javaDate = new Date(toMilliseconds (vbDate));</code>.
*
* @param comTime
* COM time.
* @return Java time.
*/
static public long convertWindowsTimeToMilliseconds(double comTime) {
long result = 0;
// code from jacobgen:
comTime = comTime - 25569D;
Calendar cal = Calendar.getInstance();
result = Math.round(86400000L * comTime)
- cal.get(Calendar.ZONE_OFFSET);
cal.setTime(new Date(result));
result -= cal.get(Calendar.DST_OFFSET);
return result;
}// convertWindowsTimeToMilliseconds()
/**
* converts a java date to a windows time object (is this timezone safe?)
*
* @param javaDate
* the java date to be converted to windows time
* @return the double representing the date in a form windows understands
*/
static public double convertDateToWindowsTime(Date javaDate) {
if (javaDate == null) {
throw new IllegalArgumentException(
"cannot convert null to windows time");
}
return convertMillisecondsToWindowsTime(javaDate.getTime());
}
/**
* Convert a Java time to a COM time.
*
* @param milliseconds
* Java time.
* @return COM time.
*/
static public double convertMillisecondsToWindowsTime(long milliseconds) {
double result = 0.0;
// code from jacobgen:
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(milliseconds);
milliseconds += (cal.get(Calendar.ZONE_OFFSET) + cal
.get(Calendar.DST_OFFSET)); // add GMT offset
result = (milliseconds / 86400000D) + 25569D;
return result;
}// convertMillisecondsToWindowsTime()
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,219 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* This class creates the scaffolding for event callbacks. Every instance of tis
* acts as a wrapper around some java object that wants callbacks from the
* microsoft side. It represents the connection between Java and COM for
* callbacks.
* <p>
* The callback mechanism will take any event that it receives and try and find
* a java method with the same name that accepts the Variant... as a parameter.
* It will then wrap the call back data in the Variant array and call the java
* method of the object that this DispatchEvents object was initialized with.
* <p>
* Instances of this class are created with "sink object" that will receive the
* event messages. The sink object is wrapped in an Invocation handler that
* actually receives the messages and then forwards them on to the "sink
* object". The constructors recognize when an instance of InvocationProxy is
* passed in and do not create a new InvocationProxy as a wrapper. They instead
* use the passed in InvocationProxy.
*
*/
public class DispatchEvents extends JacobObject {
/**
* pointer to an MS data struct. The COM layer knows the name of this
* variable and puts the windows memory pointer here.
*/
int m_pConnPtProxy = 0;
/**
* the wrapper for the event sink. This object is the one that will be sent
* a message when an event occurs in the MS layer. Normally, the
* InvocationProxy will forward the messages to a wrapped object that it
* contains.
*/
InvocationProxy mInvocationProxy = null;
/**
* This is the most commonly used constructor.
* <p>
* Creates the event callback linkage between the the MS program represented
* by the Dispatch object and the Java object that will receive the
* callback.
* <p>
* Can be used on any object that implements IProvideClassInfo.
*
* @param sourceOfEvent
* Dispatch object who's MS app will generate callbacks
* @param eventSink
* Java object that wants to receive the events
*/
public DispatchEvents(Dispatch sourceOfEvent, Object eventSink) {
this(sourceOfEvent, eventSink, null);
}
/**
* None of the samples use this constructor.
* <p>
* Creates the event callback linkage between the the MS program represented
* by the Dispatch object and the Java object that will receive the
* callback.
* <p>
* Used when the program doesn't implement IProvideClassInfo. It provides a
* way to find the TypeLib in the registry based on the programId. The
* TypeLib is looked up in the registry on the path
* HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/(CLID drived from
* progid)/ProgID/Typelib
*
* @param sourceOfEvent
* Dispatch object who's MS app will generate callbacks
* @param eventSink
* Java object that wants to receive the events
* @param progId
* program id in the registry that has a TypeLib subkey. The
* progrId is mapped to a CLSID that is they used to look up the
* key to the Typelib
*/
public DispatchEvents(Dispatch sourceOfEvent, Object eventSink,
String progId) {
this(sourceOfEvent, eventSink, progId, null);
}
/**
* Creates the event callback linkage between the the MS program represented
* by the Dispatch object and the Java object that will receive the
* callback.
* <p>
* This method was added because Excel doesn't implement IProvideClassInfo
* and the registry entry for Excel.Application doesn't include a typelib
* key.
*
* <pre>
* DispatchEvents de = new DispatchEvents(someDispatch, someEventHAndler,
* &quot;Excel.Application&quot;,
* &quot;C:\\Program Files\\Microsoft Office\\OFFICE11\\EXCEL.EXE&quot;);
* </pre>
*
* @param sourceOfEvent
* Dispatch object who's MS app will generate callbacks
* @param eventSink
* Java object that wants to receive the events
* @param progId ,
* mandatory if the typelib is specified
* @param typeLib
* The location of the typelib to use
*/
public DispatchEvents(Dispatch sourceOfEvent, Object eventSink,
String progId, String typeLib) {
if (JacobObject.isDebugEnabled()) {
System.out.println("DispatchEvents: Registering " + eventSink
+ "for events ");
}
if (eventSink instanceof InvocationProxy) {
mInvocationProxy = (InvocationProxy) eventSink;
} else {
mInvocationProxy = getInvocationProxy(eventSink);
}
if (mInvocationProxy != null) {
init3(sourceOfEvent, mInvocationProxy, progId, typeLib);
} else {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("Cannot register null event sink for events");
}
throw new IllegalArgumentException(
"Cannot register null event sink for events");
}
}
/**
* Returns an instance of the proxy configured with pTargetObject as its
* target
*
* @param pTargetObject
* @return InvocationProxy an instance of the proxy this DispatchEvents will
* send to the COM layer
*/
protected InvocationProxy getInvocationProxy(Object pTargetObject) {
InvocationProxy newProxy = new InvocationProxyAllVariants();
newProxy.setTarget(pTargetObject);
return newProxy;
}
/**
* hooks up a connection point proxy by progId event methods on the sink
* object will be called by name with a signature of <name>(Variant[] args)
*
* You must specify the location of the typeLib.
*
* @param src
* dispatch that is the source of the messages
* @param sink
* the object that will receive the messages
* @param progId
* optional program id. most folks don't need this either
* @param typeLib
* optional parameter for those programs that don't register
* their type libs (like Excel)
*/
private native void init3(Dispatch src, Object sink, String progId,
String typeLib);
/**
* now private so only this object can asccess was: call this to explicitly
* release the com object before gc
*
*/
private native void release();
/*
* (non-Javadoc)
*
* @see java.lang.Object#finalize()
*/
protected void finalize() {
safeRelease();
}
/*
* (non-Javadoc)
*
* @see com.jacob.com.JacobObject#safeRelease()
*/
public void safeRelease() {
if (mInvocationProxy != null) {
mInvocationProxy.setTarget(null);
}
mInvocationProxy = null;
super.safeRelease();
if (m_pConnPtProxy != 0) {
release();
m_pConnPtProxy = 0;
} else {
// looks like a double release
if (isDebugEnabled()) {
debug("DispatchEvents:" + this.hashCode() + " double release");
}
}
}
}

View File

@@ -0,0 +1,82 @@
/**
*
*/
package com.jacob.com;
/**
* A bunch of DispatchIds that were pulled out of the Dispatch class for version
* 1.14.
*/
public class DispatchIdentifier {
private DispatchIdentifier() {
// This is utility class so there is no constructor.
}
public static final int DISPID_UNKNOWN = -1;
public static final int DISPID_VALUE = 0;
public static final int DISPID_PROPERTYPUT = -3;
public static final int DISPID_NEWENUM = -4;
public static final int DISPID_EVALUATE = -5;
public static final int DISPID_CONSTRUCTOR = -6;
public static final int DISPID_DESTRUCTOR = -7;
public static final int DISPID_COLLECT = -8;
public static final int DISPID_AUTOSIZE = -500;
public static final int DISPID_BACKCOLOR = -501;
public static final int DISPID_BACKSTYLE = -502;
public static final int DISPID_BORDERCOLOR = -503;
public static final int DISPID_BORDERSTYLE = -504;
public static final int DISPID_BORDERWIDTH = -505;
public static final int DISPID_DRAWMODE = -507;
public static final int DISPID_DRAWSTYLE = -508;
public static final int DISPID_DRAWWIDTH = -509;
public static final int DISPID_FILLCOLOR = -510;
public static final int DISPID_FILLSTYLE = -511;
public static final int DISPID_FONT = -512;
public static final int DISPID_FORECOLOR = -513;
public static final int DISPID_ENABLED = -514;
public static final int DISPID_HWND = -515;
public static final int DISPID_TABSTOP = -516;
public static final int DISPID_TEXT = -517;
public static final int DISPID_CAPTION = -518;
public static final int DISPID_BORDERVISIBLE = -519;
public static final int DISPID_APPEARANCE = -520;
public static final int DISPID_MOUSEPOINTER = -521;
public static final int DISPID_MOUSEICON = -522;
public static final int DISPID_PICTURE = -523;
public static final int DISPID_VALID = -524;
public static final int DISPID_READYSTATE = -525;
public static final int DISPID_REFRESH = -550;
public static final int DISPID_DOCLICK = -551;
public static final int DISPID_ABOUTBOX = -552;
public static final int DISPID_CLICK = -600;
public static final int DISPID_DBLCLICK = -601;
public static final int DISPID_KEYDOWN = -602;
public static final int DISPID_KEYPRESS = -603;
public static final int DISPID_KEYUP = -604;
public static final int DISPID_MOUSEDOWN = -605;
public static final int DISPID_MOUSEMOVE = -606;
public static final int DISPID_MOUSEUP = -607;
public static final int DISPID_ERROREVENT = -608;
public static final int DISPID_READYSTATECHANGE = -609;
public static final int DISPID_AMBIENT_BACKCOLOR = -701;
public static final int DISPID_AMBIENT_DISPLAYNAME = -702;
public static final int DISPID_AMBIENT_FONT = -703;
public static final int DISPID_AMBIENT_FORECOLOR = -704;
public static final int DISPID_AMBIENT_LOCALEID = -705;
public static final int DISPID_AMBIENT_MESSAGEREFLECT = -706;
public static final int DISPID_AMBIENT_SCALEUNITS = -707;
public static final int DISPID_AMBIENT_TEXTALIGN = -708;
public static final int DISPID_AMBIENT_USERMODE = -709;
public static final int DISPID_AMBIENT_UIDEAD = -710;
public static final int DISPID_AMBIENT_SHOWGRABHANDLES = -711;
public static final int DISPID_AMBIENT_SHOWHATCHING = -712;
public static final int DISPID_AMBIENT_DISPLAYASDEFAULT = -713;
public static final int DISPID_AMBIENT_SUPPORTSMNEMONICS = -714;
public static final int DISPID_AMBIENT_AUTOCLIP = -715;
public static final int DISPID_AMBIENT_APPEARANCE = -716;
public static final int DISPID_AMBIENT_CODEPAGE = -725;
public static final int DISPID_AMBIENT_PALETTE = -726;
public static final int DISPID_AMBIENT_CHARSET = -727;
public static final int DISPID_AMBIENT_TRANSFERPRIORITY = -728;
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* If you need to pass a COM Dispatch object between STA threads, you have to
* marshall the interface. This class is used as follows: the STA that creates
* the Dispatch object must construct an instance of this class. Another thread
* can then call toDispatch() on that instance and get a Dispatch pointer which
* has been marshalled. WARNING: You can only call toDispatch() once! If you
* need to call it multiple times (or from multiple threads) you need to
* construct a separate DispatchProxy instance for each such case!
*/
public class DispatchProxy extends JacobObject {
/**
* Comment for <code>m_pStream</code>
*/
public int m_pStream;
/**
* Marshals the passed in dispatch into the stream
*
* @param localDispatch
*/
public DispatchProxy(Dispatch localDispatch) {
MarshalIntoStream(localDispatch);
}
/**
*
* @return Dispatch the dispatch retrieved from the stream
*/
public Dispatch toDispatch() {
return MarshalFromStream();
}
private native void MarshalIntoStream(Dispatch d);
private native Dispatch MarshalFromStream();
/**
* now private so only this object can access was: call this to explicitly
* release the com object before gc
*
*/
private native void release();
/*
* (non-Javadoc)
*
* @see java.lang.Object#finalize()
*/
public void finalize() {
safeRelease();
}
/*
* (non-Javadoc)
*
* @see com.jacob.com.JacobObject#safeRelease()
*/
public void safeRelease() {
super.safeRelease();
if (m_pStream != 0) {
release();
m_pStream = 0;
} else {
// looks like a double release
if (isDebugEnabled()) {
debug(this.getClass().getName() + ":" + this.hashCode()
+ " double release");
}
}
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* An implementation of IEnumVariant based on code submitted by Thomas Hallgren
* (mailto:Thomas.Hallgren@eoncompany.com)
*/
public class EnumVariant extends JacobObject implements
java.util.Enumeration<Variant> {
private int m_pIEnumVARIANT;
private final Variant[] m_recBuf = new Variant[1];
// this only gets called from JNI
//
protected EnumVariant(int pIEnumVARIANT) {
m_pIEnumVARIANT = pIEnumVARIANT;
}
/**
* @param disp
*/
public EnumVariant(Dispatch disp) {
int[] hres = new int[1];
Variant evv = Dispatch.invokev(disp, DispatchIdentifier.DISPID_NEWENUM,
Dispatch.Get, new Variant[0], hres);
if (evv.getvt() != Variant.VariantObject)
//
// The DISPID_NEWENUM did not result in a valid object
//
throw new ComFailException("Can't obtain EnumVARIANT");
EnumVariant tmp = evv.toEnumVariant();
m_pIEnumVARIANT = tmp.m_pIEnumVARIANT;
tmp.m_pIEnumVARIANT = 0;
}
/**
* Implements java.util.Enumeration
*
* @return boolean true if there are more elements in this enumeration
*/
public boolean hasMoreElements() {
{
if (m_recBuf[0] == null) {
if (this.Next(m_recBuf) <= 0)
return false;
}
return true;
}
}
/**
* Implements java.util.Enumeration
*
* @return next element in the enumeration
*/
public Variant nextElement() {
Variant last = m_recBuf[0];
if (last == null) {
if (this.Next(m_recBuf) <= 0)
throw new java.util.NoSuchElementException();
last = m_recBuf[0];
}
m_recBuf[0] = null;
return last;
}
/**
* Get next element in collection or null if at end
*
* @return Variant that is next in the collection
* @deprecated use nextElement() instead
*/
@Deprecated
public Variant Next() {
if (hasMoreElements())
return nextElement();
return null;
}
/**
* This should be private and wrapped to protect JNI layer.
*
* @param receiverArray
* @return Returns the next variant object pointer as an int from windows
* layer
*/
public native int Next(Variant[] receiverArray);
/**
* This should be private and wrapped to protect JNI layer.
*
* @param count
* number to skip
*/
public native void Skip(int count);
/**
* This should be private and wrapped to protect JNI layer
*/
public native void Reset();
/**
* now private so only this object can access was: call this to explicitly
* release the com object before gc
*
*/
private native void release();
/*
* (non-Javadoc)
*
* @see java.lang.Object#finalize()
*/
protected void finalize() {
safeRelease();
}
/*
* (non-Javadoc)
*
* @see com.jacob.com.JacobObject#safeRelease()
*/
public void safeRelease() {
super.safeRelease();
if (m_pIEnumVARIANT != 0) {
this.release();
m_pIEnumVARIANT = 0;
} else {
// looks like a double release
if (isDebugEnabled()) {
debug(this.getClass().getName() + ":" + this.hashCode()
+ " double release");
}
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* @version $Id$
* @author joe
*
* DispatchEvents wraps this class around any event handlers before making the
* JNI call that sets up the link with EventProxy. This means that
* EventProxy.cpp just calls invoke(String,Variant[]) against the instance of
* this class. Then this class does reflection against the event listener to
* call the actual event methods. The event methods can return void or return a
* Variant. Any value returned will be passed back to the calling windows module
* by the Jacob JNI layer.
* <p>
*
* The void returning signature is the standard legacy signature. The Variant
* returning signature was added in 1.10 to support event handlers returning
* values.
*
*/
public abstract class InvocationProxy {
/**
* the object we will try and forward to.
*/
protected Object mTargetObject = null;
/**
* dummy constructor for subclasses that don't actually wrap anything and
* just want to override the invoke() method
*/
protected InvocationProxy() {
super();
}
/**
* The method actually invoked by EventProxy.cpp. The method name is
* calculated by the underlying JNI code from the MS windows Callback
* function name. The method is assumed to take an array of Variant objects.
* The method may return a Variant or be a void. Those are the only two
* options that will not blow up.
* <p>
* Subclasses that override this should make sure mTargetObject is not null
* before processing.
*
* @param methodName
* name of method in mTargetObject we will invoke
* @param targetParameters
* Variant[] that is the single parameter to the method
* @return an object that will be returned to the com event caller
*/
public abstract Variant invoke(String methodName,
Variant targetParameters[]);
/**
* used by EventProxy.cpp to create variant objects in the right thread
*
* @return Variant object that will be used by the COM layer
*/
public Variant getVariant() {
return new VariantViaEvent();
}
/**
* Sets the target for this InvocationProxy.
*
* @param pTargetObject
* @throws IllegalArgumentException
* if target is not publicly accessible
*/
public void setTarget(Object pTargetObject) {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("InvocationProxy: setting target "
+ pTargetObject);
}
if (pTargetObject != null) {
// JNI code apparently bypasses this check and could operate against
// protected classes. This seems like a security issue...
// maybe it was because JNI code isn't in a package?
if (!java.lang.reflect.Modifier.isPublic(pTargetObject.getClass()
.getModifiers())) {
throw new IllegalArgumentException(
"InvocationProxy only public classes can receive event notifications");
}
}
mTargetObject = pTargetObject;
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* This class acts as a proxy between the windows event callback mechanism and
* the Java classes that are looking for events. It assumes that all of the Java
* classes that are looking for events implement methods with the same names as
* the windows events and that the implemented methods accept an array of
* variant objects. The methods can return void or a Variant that will be
* returned to the calling layer. All Event methods that will be recognized by
* InvocationProxyAllEvents have the signature
*
* <code> void eventMethodName(Variant[])</code> or
* <code> Variant eventMethodName(Variant[])</code>
*/
public class InvocationProxyAllVariants extends InvocationProxy {
/*
* (non-Javadoc)
*
* @see com.jacob.com.InvocationProxy#invoke(java.lang.String,
* com.jacob.com.Variant[])
*/
@SuppressWarnings("unchecked")
public Variant invoke(String methodName, Variant targetParameters[]) {
Variant mVariantToBeReturned = null;
if (mTargetObject == null) {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("InvocationProxy: received notification ("
+ methodName + ") with no target set");
}
// structured programming guidlines say this return should not be up
// here
return null;
}
Class targetClass = mTargetObject.getClass();
if (methodName == null) {
throw new IllegalArgumentException(
"InvocationProxy: missing method name");
}
if (targetParameters == null) {
throw new IllegalArgumentException(
"InvocationProxy: missing Variant parameters");
}
try {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("InvocationProxy: trying to invoke "
+ methodName + " on " + mTargetObject);
}
Method targetMethod;
targetMethod = targetClass.getMethod(methodName,
new Class[] { Variant[].class });
if (targetMethod != null) {
// protected classes can't be invoked against even if they
// let you grab the method. you could do
// targetMethod.setAccessible(true);
// but that should be stopped by the security manager
Object mReturnedByInvocation = null;
mReturnedByInvocation = targetMethod.invoke(mTargetObject,
new Object[] { targetParameters });
if (mReturnedByInvocation == null) {
mVariantToBeReturned = null;
} else if (!(mReturnedByInvocation instanceof Variant)) {
// could try and convert to Variant here.
throw new IllegalArgumentException(
"InvocationProxy: invokation of target method returned "
+ "non-null non-variant object: "
+ mReturnedByInvocation);
} else {
mVariantToBeReturned = (Variant) mReturnedByInvocation;
}
}
} catch (SecurityException e) {
// what causes this exception?
e.printStackTrace();
} catch (NoSuchMethodException e) {
// this happens whenever the listener doesn't implement all the
// methods
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("InvocationProxy: listener (" + mTargetObject
+ ") doesn't implement " + methodName);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
// we can throw these inside the catch block so need to re-throw it
throw e;
} catch (IllegalAccessException e) {
// can't access the method on the target instance for some reason
if (JacobObject.isDebugEnabled()) {
JacobObject
.debug("InvocationProxy: probably tried to access public method on non public class"
+ methodName);
}
e.printStackTrace();
} catch (InvocationTargetException e) {
// invocation of target method failed
e.printStackTrace();
}
return mVariantToBeReturned;
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* The parent class of all Jacob exceptions. They all used to be based off of
* RuntimeException or ComException but it was decided to base them all off of
* one owned by this project.
*/
public class JacobException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = -1637125318746002715L;
/**
* Default constructor. Calls super with a "No Message Provided" string
*/
public JacobException() {
super("No Message Provided");
}
/**
* standard constructor
*
* @param message
*/
public JacobException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* The superclass of all Jacob objects. It is used to create a standard API
* framework and to facilitate memory management for Java and COM memory
* elements.
* <p>
* All instances of this class and subclasses are automatically managed by the
* ROT. This means the ROT cannot be a subclass of JacobObject.
* <p>
* All COM object created by JACOB extend this class so that we can
* automatically release them when the thread is detached from COM - if we leave
* it to the finalizer it will call the release from another thread, which may
* result in a segmentation violation.
*/
public class JacobObject {
/**
* Standard constructor that adds this JacobObject to the memory management
* pool.
*/
public JacobObject() {
ROT.addObject(this);
}
/**
* Finalizers call this method. This method should release any COM data
* structures in a way that it can be called multiple times. This can happen
* if someone manually calls this and then a finalizer calls it.
*/
public void safeRelease() {
// currently does nothing - subclasses may do something
if (isDebugEnabled()) {
// this used to do a toString() but that is bad for SafeArray
debug("SafeRelease: " + this.getClass().getName());
}
}
/**
* When things go wrong, it is useful to be able to debug the ROT.
*/
private static final boolean DEBUG =
// true;
"true".equalsIgnoreCase(System.getProperty("com.jacob.debug"));
protected static boolean isDebugEnabled() {
// return true;
return DEBUG;
}
/**
* Loads JacobVersion.Properties and returns the value of version in it
*
* @deprecated use JacobReleaseInfo.getBuildDate() instead.
* @return String value of version in JacobVersion.Properties or "" if none
*/
@Deprecated
public static String getBuildDate() {
return JacobReleaseInfo.getBuildDate();
}
/**
* Loads JacobVersion.Properties and returns the value of version in it
*
* @deprecated use JacobReleaseInfo.getBuildVersion() instead.
* @return String value of version in JacobVersion.Properties or "" if none
*/
@Deprecated
public static String getBuildVersion() {
return JacobReleaseInfo.getBuildVersion();
}
/**
* Very basic debugging function.
*
* @param istrMessage
*/
protected static void debug(String istrMessage) {
if (isDebugEnabled()) {
System.out.println(Thread.currentThread().getName() + ": "
+ istrMessage);
}
}
/**
* force the jacob DLL to be loaded whenever this class is referenced
*/
static {
LibraryLoader.loadJacobLibrary();
}
}

View File

@@ -0,0 +1,96 @@
package com.jacob.com;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* An interface to the version properties file. This code was removed from
* JacobObject because it doesn't belong there.
*
*/
public class JacobReleaseInfo {
/**
* holds the build version as retrieved from the version properties file
* that exists in the JAR. This can be retrieved by calling the static
* method getBuildVersion()
*
* @see #getBuildVersion()
*/
private static String buildVersion = "";
/**
* holds the build date as retrieved from the version properties file that
* exists in the JAR This can be retrieved by calling the static method
* getBuildDate()
*
* @see #getBuildDate()
*/
private static String buildDate = "";
/** the name of the jacob version properties file */
private static final String PROPERTY_FILE_NAME = "META-INF/JacobVersion.properties";
/**
* Loads version information from PROPERTY_FILE_NAME that was built as part
* of this release.
*
* @throws IllegalStateException
* when it can't find the version properties file
*/
private static void loadVersionProperties() {
Properties versionProps = new Properties();
// can't use system class loader cause won't work in JavaWebStart
InputStream stream = JacobReleaseInfo.class.getClassLoader()
.getResourceAsStream(PROPERTY_FILE_NAME);
// This should never happen. This is an attempt to make something work
// for WebSphere. They may be using some kind of Servlet loader that
// needs an absolute path based search
if (stream == null) {
stream = JacobReleaseInfo.class.getClassLoader()
.getResourceAsStream("/" + PROPERTY_FILE_NAME);
}
// A report came in that WebSphere had trouble finding the file
// so lets trap it. Plus, it's a good idea anyway.
if (stream == null) {
throw new IllegalStateException(
"Can't find "
+ PROPERTY_FILE_NAME
+ " using JacobReleaseInfo.class.getClassLoader().getResourceAsStream()");
} else {
try {
versionProps.load(stream);
stream.close();
buildVersion = (String) versionProps.get("version");
buildDate = (String) versionProps.get("build.date");
} catch (IOException ioe) {
ioe.printStackTrace();
System.err.println("Warning! Couldn't load props " + ioe);
}
}
}
/**
* loads PROPERT_FILE_NAME and returns the value of version in it
*
* @return String value of version in PROPERT_FILE_NAME or "" if none
*/
public static String getBuildDate() {
if (buildDate.equals("")) {
loadVersionProperties();
}
return buildDate;
}
/**
* loads PROPERT_FILE_NAME and returns the value of version in it
*
* @return String value of version in PROPERT_FILE_NAME or "" if none
*/
public static String getBuildVersion() {
if (buildVersion.equals("")) {
loadVersionProperties();
}
return buildVersion;
}
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright (c) 1999-2007 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
/**
* Utility class to centralize the way in which the jacob JNI library is loaded.
* <p>
*
* This supports defining the path or library name using system properties or a
* custom resource file. If desired, jacob can auto-detect the correct version
* of the DLL for 32 or 64 bit windows, as long as you have named them
* differently.
*
* <ol>
* <li> If system property {@link #JACOB_DLL_PATH} is defined, the file located
* there will be loaded as the jacob dll using System.load(). </li>
*
* <li> If system property {@link #JACOB_DLL_NAME} is defined, the file located
* there will be loaded as the jacob dll. </li>
* <li> If system property {@link #JACOB_DLL_NAME_X86} and
* {@link #JACOB_DLL_NAME_X64} are defined, the file located there will be
* loaded as the jacob dll, depending on the version of Windows. </li>
*
* <li> If {@link #JACOB_DLL_NAME} is defined in the
* {@code com.jacob.com.JacobLibraryLoader} resource file, the specified dll
* will be loaded from the {@code java.library.path}. </li>
* <li> If {@link #JACOB_DLL_NAME_X86} and {@link #JACOB_DLL_NAME_X64} are
* defined in the {@code com.jacob.com.JacobLibraryLoader} resource file, the
* specified dll will be loaded from the {@code java.library.path}, depending
* on the version of Windows. </li>
*
* <li> If none of the above are true, the default is to load the library named
* "jacob-&lt;version&gt;-&lt;arch&gt" (or
* "jacob-&lt;version&gt;-&lt;arch&rt;.dll") from the {@code java.library.path}.
* </li>
* </ol>
*
* The standard behavior for most applications is that {@code LoadLibrary()}
* will be called to load the dll. {@code LoadLibary()} searches directories
* specified in the variable {@code java.library.path}. This is why most test
* cases specify -Djava.library.path in their command line arguments.
* <p>
* JACOB_DLL_PATH submitted sourceforge ticket 1493647 Added 1.11 <br>
* JACOB_DLL_NAME, JACOB_DLL_NAME_32, JACOB_DLL_NAME_64 submitted sourceforge
* ticket 1845039 Added 1.14M7
*
* @author Scott Dickerson (sjd78)
* @author Jason Smith
*/
public final class LibraryLoader {
/**
* Name of system property (currently <tt>jacob.dll.path</tt>) that may
* contain an absolute path to the JNI library.
*/
public static final String JACOB_DLL_PATH = "jacob.dll.path";
/**
* Name of system property (currently <tt>jacob.dll.name</tt>) that may
* contain an alternate name for the JNI library (default is 'jacob').
*/
public static final String JACOB_DLL_NAME = "jacob.dll.name";
/**
* Name of system property (currently <tt>jacob.dll.name</tt>) that may
* contain an alternate name for the JNI library (default is 'jacob'), 32
* bit windows.
*/
public static final String JACOB_DLL_NAME_X86 = "jacob.dll.name.x86";
/**
* Name of system property (currently <tt>jacob.dll.name</tt>) that may
* contain an alternate name for the JNI library (default is 'jacob'), 64
* bit windows.
*/
public static final String JACOB_DLL_NAME_X64 = "jacob.dll.name.x64";
/**
* Appended to "jacob" when building DLL name This string must EXACTLY match
* the string in the build.xml file
*/
public static final String DLL_NAME_MODIFIER_32_BIT = "x86";
/**
* Appended to "jacob" when building DLL name This string must EXACTLY match
* the string in the build.xml file
*/
public static final String DLL_NAME_MODIFIER_64_BIT = "x64";
/**
* Load the jacob dll either from an absolute path or by a library name,
* both of which may be defined in various ways.
*
* @throws UnsatisfiedLinkError
* if the library does not exist.
*/
public static void loadJacobLibrary() {
// In some cases, a library that uses Jacob won't be able to set system
// properties
// prior to Jacob being loaded. The resource bundle provides an
// alternate way to
// override DLL name or path that will be loaded with Jacob regardless
// of other
// initialization order.
ResourceBundle resources = null;
Set<String> keys = new HashSet<String>();
try {
resources = ResourceBundle.getBundle(LibraryLoader.class.getName(),
Locale.getDefault(), LibraryLoader.class.getClassLoader());
for (Enumeration<String> i = resources.getKeys(); i
.hasMoreElements();) {
String key = i.nextElement();
keys.add(key);
}
} catch (MissingResourceException e) {
// Do nothing. Expected.
}
// First, check for a defined PATH. System property overrides resource
// bundle.
String path = System.getProperty(JACOB_DLL_PATH);
if (path == null && resources != null && keys.contains(JACOB_DLL_PATH)) {
path = (String) resources.getObject(JACOB_DLL_PATH);
}
if (path != null) {
JacobObject.debug("Loading library " + path
+ " using System.loadLibrary ");
System.load(path);
} else {
// Path was not defined, so use the OS mechanism for loading
// libraries.
// Check for a defined NAME. System property overrides resource
// bundle.
String name = null;
if (System.getProperty(JACOB_DLL_NAME) != null) {
name = System.getProperty(JACOB_DLL_NAME);
} else if (System.getProperty(JACOB_DLL_NAME_X86) != null
&& shouldLoad32Bit()) {
name = System.getProperty(JACOB_DLL_NAME_X86);
} else if (System.getProperty(JACOB_DLL_NAME_X64) != null
&& !shouldLoad32Bit()) {
name = System.getProperty(JACOB_DLL_NAME_X64);
} else if (resources != null && keys.contains(JACOB_DLL_NAME)) {
name = resources.getString(JACOB_DLL_NAME);
} else if (resources != null && keys.contains(JACOB_DLL_NAME_X86)
&& shouldLoad32Bit()) {
name = resources.getString(JACOB_DLL_NAME_X86);
} else if (resources != null && keys.contains(JACOB_DLL_NAME_X64)
&& !shouldLoad32Bit()) {
name = resources.getString(JACOB_DLL_NAME_X64);
} else {
// No alternate NAME or PATH was defined, so use the default.
// We will almost always end up here.
name = getPreferredDLLName();
}
JacobObject.debug("Loading library " + name
+ " using System.loadLibrary ");
// System.out.println("Loading " + name);
System.loadLibrary(name);
}
}
/**
* Developer note: This method MUST be synchronized with the DLL names
* created as part of the build process in build.xml
* <p>
* The DLL name is "jacob\<PLATFORM\>.release"
*
* @return the preferred name of the DLL adjusted for this platform and
* version without the ".dll" extension
*/
public static String getPreferredDLLName() {
if (shouldLoad32Bit()) {
return "jacob" + "-" + JacobReleaseInfo.getBuildVersion() + "-"
+ DLL_NAME_MODIFIER_32_BIT;
} else {
return "jacob" + "-" + JacobReleaseInfo.getBuildVersion() + "-"
+ DLL_NAME_MODIFIER_64_BIT;
}
}
/**
* Detects whether this is a 32-bit JVM.
*
* @return {@code true} if this is a 32-bit JVM.
*/
protected static boolean shouldLoad32Bit() {
// This guesses whether we are running 32 or 64 bit Java.
// This works for Sun and IBM JVMs version 5.0 or later.
// May need to be adjusted for non-Sun JVMs.
String bits = System.getProperty("sun.arch.data.model", "?");
if (bits.equals("32"))
return true;
else if (bits.equals("64"))
return false;
// this works for jRocket
String arch = System.getProperty("java.vm.name", "?");
if (arch.toLowerCase().indexOf("64-bit") >= 0)
return false;
return true;
}
} // LibraryLoader

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* We provide our own main sta thread to avoid COM tagging a random thread as
* the main STA - this is the thread in which all Apartment threaded components
* will be created if the client chooses an MTA threading model for the java
* side of the app.
*/
public class MainSTA extends STA {
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* Thrown by java APIs that are not implemented either because they were never
* implemented or because they are being deprecated This is a subclass of
* ComException so callers can still just catch ComException.
*/
public class NotImplementedException extends JacobException {
/**
*
*/
private static final long serialVersionUID = -9169900832852356445L;
/**
* @param description
*/
public NotImplementedException(String description) {
super(description);
}
}

View File

@@ -0,0 +1,279 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
/**
* The Running Object Table (ROT) maps each thread to a collection of all the
* JacobObjects that were created in that thread. It always operates on the
* current thread so all the methods are static and they implicitly get the
* current thread.
* <p>
* The clearObjects method is used to release all the COM objects created by
* Jacob in the current thread prior to uninitializing COM for that thread.
* <p>
* Prior to 1.9, manual garbage collection was the only option in Jacob, but
* from 1.9 onward, setting the com.jacob.autogc system property allows the
* objects referenced by the ROT to be automatically GCed. Automatic GC may be
* preferable in systems with heavy event callbacks.
* <p>
* Is [ 1116101 ] jacob-msg 0284 relevant???
*/
public abstract class ROT {
/**
* Manual garbage collection was the only option pre 1.9 Can staticly cache
* the results because only one value and we don't let it change during a
* run
*/
protected static final boolean USE_AUTOMATIC_GARBAGE_COLLECTION = "true"
.equalsIgnoreCase(System.getProperty("com.jacob.autogc"));
/**
* If the code is ran from an applet that is called from javascript the Java
* Plugin does not give full permissions to the code and thus System
* properties cannot be accessed. They can be accessed at class
* initialization time.
*
* The default behavior is to include all classes in the ROT, setting a
* boolean here to indicate this prevents a call to System.getProperty as
* part of the general call flow.
*/
protected static final Boolean INCLUDE_ALL_CLASSES_IN_ROT = Boolean
.valueOf(System.getProperty("com.jacob.includeAllClassesInROT",
"true"));
/**
* Suffix added to class name to make up property name that determines if
* this object should be stored in the ROT. This 1.13 "feature" makes it
* possible to cause VariantViaEvent objects to not be added to the ROT in
* event callbacks.
* <p>
* We don't have a static for the actual property because there is a
* different property for each class that may make use of this feature.
*/
protected static String PUT_IN_ROT_SUFFIX = ".PutInROT";
/**
* A hash table where each element is another HashMap that represents a
* thread. Each thread HashMap contains the com objects created in that
* thread
*/
private static HashMap<String, Map<JacobObject, String>> rot = new HashMap<String, Map<JacobObject, String>>();
/**
* adds a new thread storage area to rot
*
* @return Map corresponding to the thread that this call was made in
*/
protected synchronized static Map<JacobObject, String> addThread() {
// should use the id here instead of the name because the name can be
// changed
String t_name = Thread.currentThread().getName();
if (rot.containsKey(t_name)) {
// nothing to do
} else {
Map<JacobObject, String> tab = null;
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ROT: Automatic GC flag == "
+ USE_AUTOMATIC_GARBAGE_COLLECTION);
}
if (!USE_AUTOMATIC_GARBAGE_COLLECTION) {
tab = new HashMap<JacobObject, String>();
} else {
tab = new WeakHashMap<JacobObject, String>();
}
rot.put(t_name, tab);
}
return getThreadObjects(false);
}
/**
* Returns the pool for this thread if it exists. can create a new one if
* you wish by passing in TRUE
*
* @param createIfDoesNotExist
* @return Map the collection that holds the objects created in the current
* thread
*/
protected synchronized static Map<JacobObject, String> getThreadObjects(
boolean createIfDoesNotExist) {
String t_name = Thread.currentThread().getName();
if (!rot.containsKey(t_name) && createIfDoesNotExist) {
addThread();
}
return rot.get(t_name);
}
/**
* Iterates across all of the entries in the Hashmap in the rot that
* corresponds to this thread. This calls safeRelease() on each entry and
* then clears the map when done and removes it from the rot. All traces of
* this thread's objects will disappear. This is called by COMThread in the
* tear down and provides a synchronous way of releasing memory
*/
protected static void clearObjects() {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ROT: " + rot.keySet().size()
+ " thread tables exist");
}
Map<JacobObject, String> tab = getThreadObjects(false);
if (tab != null) {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ROT: " + tab.keySet().size()
+ " objects to clear in this thread's ROT ");
}
// walk the values
Iterator<JacobObject> it = tab.keySet().iterator();
while (it.hasNext()) {
JacobObject o = it.next();
if (o != null
// can't use this cause creates a Variant if calling SafeAray
// and we get an exception modifying the collection while
// iterating
// && o.toString() != null
) {
if (JacobObject.isDebugEnabled()) {
if (o instanceof SafeArray) {
// SafeArray create more objects when calling
// toString()
// which causes a concurrent modification exception
// in HashMap
JacobObject.debug("ROT: removing "
+ o.getClass().getName());
} else {
// Variant toString() is probably always bad in here
JacobObject.debug("ROT: removing " + o.hashCode()
+ "->" + o.getClass().getName());
}
}
o.safeRelease();
}
}
// empty the collection
tab.clear();
// remove the collection from rot
ROT.removeThread();
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ROT: thread table cleared and removed");
}
} else {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ROT: nothing to clear!");
}
}
}
/**
* Removes the map from the rot that is associated with the current thread.
*/
private synchronized static void removeThread() {
// should this see if it exists first?
rot.remove(Thread.currentThread().getName());
}
/**
* @deprecated the java model leave the responsibility of clearing up
* objects to the Garbage Collector. Our programming model
* should not require that the user specifically remove object
* from the thread. <br>
* This will remove an object from the ROT <br>
* This does not need to be synchronized because only the rot
* modification related methods need to synchronized. Each
* individual map is only modified in a single thread.
* @param o
*/
@Deprecated
protected static void removeObject(JacobObject o) {
Map<JacobObject, String> tab = ROT.getThreadObjects(false);
if (tab != null) {
tab.remove(o);
}
o.safeRelease();
}
/**
* Adds an object to the HashMap for the current thread. <br>
* <p>
* This method does not need to be threaded because the only concurrent
* modification risk is on the hash map that contains all of the thread
* related hash maps. The individual thread related maps are only used on a
* per thread basis so there isn't a locking issue.
* <p>
* In addition, this method cannot be threaded because it calls
* ComThread.InitMTA. The ComThread object has some methods that call ROT so
* we could end up deadlocked. This method should be safe without the
* synchronization because the ROT works on per thread basis and the methods
* that add threads and remove thread related entries are all synchronized
*
*
* @param o
*/
protected static void addObject(JacobObject o) {
String shouldIncludeClassInROT = "true";
// only call System.getProperty if we are not including all classes in
// the ROT. This lets us run with standard Jacob behavior in Applets
// without the security exception raised by System.getProperty in the
// flow
if (!ROT.INCLUDE_ALL_CLASSES_IN_ROT) {
shouldIncludeClassInROT = System.getProperty(o.getClass().getName()
+ PUT_IN_ROT_SUFFIX, "true");
}
if (shouldIncludeClassInROT.equalsIgnoreCase("false")) {
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("JacobObject: New instance of "
+ o.getClass().getName() + " not added to ROT");
}
} else {
// first see if we have a table for this thread
Map<JacobObject, String> tab = getThreadObjects(false);
if (tab == null) {
// this thread has not been initialized as a COM thread
// so make it part of MTA for backwards compatibility
ComThread.InitMTA(false);
// don't really need the "true" because the InitMTA will have
// called back to the ROT to create a table for this thread
tab = getThreadObjects(true);
}
if (JacobObject.isDebugEnabled()) {
JacobObject.debug("ROT: adding " + o + "->"
+ o.getClass().getName()
+ " table size prior to addition:" + tab.size());
}
// add the object to the table that is specific to this thread
if (tab != null) {
tab.put(o, null);
}
}
}
/**
* ROT can't be a subclass of JacobObject because of the way ROT pools are
* managed so we force a DLL load here by referencing JacobObject
*/
static {
LibraryLoader.loadJacobLibrary();
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* A class that implements a Single Threaded Apartment. Users will subclass this
* and override OnInit() and OnQuit() where they will create and destroy a COM
* component that wants to run in an STA other than the main STA.
*/
public class STA extends Thread {
/**
* referenced by STA.cpp
*/
public int threadID;
/**
* constructor for STA
*/
public STA() {
start(); // start the thread
}
/*
* (non-Javadoc)
*
* @see java.lang.Thread#run()
*/
public void run() {
// init COM
ComThread.InitSTA();
if (OnInit()) {
// this call blocks in the win32 message loop
// until quitMessagePump is called
doMessagePump();
}
OnQuit();
// uninit COM
ComThread.Release();
}
/**
* Override this method to create and initialize any COM component that you
* want to run in this thread. If anything fails, return false to terminate
* the thread.
*
* @return always returns true
*/
public boolean OnInit() {
return true;
}
/**
* Override this method to destroy any resource before the thread exits and
* COM in uninitialized
*/
public void OnQuit() {
// there is nothing to see here
}
/**
* calls quitMessagePump
*/
public void quit() {
quitMessagePump();
}
/**
* run a message pump for the main STA
*/
public native void doMessagePump();
/**
* quit message pump for the main STA
*/
public native void quitMessagePump();
/**
* STA isn't a subclass of JacobObject so a reference to it doesn't load the
* DLL without this
*/
static {
LibraryLoader.loadJacobLibrary();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,497 @@
/**
*
*/
package com.jacob.com;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.Date;
/**
* A utility class used to convert between Java objects and Variants
*/
public final class VariantUtilities {
private VariantUtilities() {
// utility class with only static methods don't need constructors
}
/**
* Populates a variant object from a java object. This method attempts to
* figure out the appropriate Variant type
*
* @param targetVariant
* @param pValueObject
* @param fByRef
*/
protected static void populateVariant(Variant targetVariant,
Object pValueObject, boolean fByRef) {
if (pValueObject == null) {
targetVariant.putEmpty();
} else if (pValueObject instanceof Integer) {
if (fByRef) {
targetVariant.putIntRef(((Integer) pValueObject).intValue());
} else {
targetVariant.putInt(((Integer) pValueObject).intValue());
}
} else if (pValueObject instanceof Short) {
if (fByRef) {
targetVariant.putShortRef(((Short) pValueObject).shortValue());
} else {
targetVariant.putShort(((Short) pValueObject).shortValue());
}
} else if (pValueObject instanceof String) {
if (fByRef) {
targetVariant.putStringRef((String) pValueObject);
} else {
targetVariant.putString((String) pValueObject);
}
} else if (pValueObject instanceof Boolean) {
if (fByRef) {
targetVariant.putBooleanRef(((Boolean) pValueObject)
.booleanValue());
} else {
targetVariant.putBoolean(((Boolean) pValueObject)
.booleanValue());
}
} else if (pValueObject instanceof Double) {
if (fByRef) {
targetVariant.putDoubleRef(((Double) pValueObject)
.doubleValue());
} else {
targetVariant.putDouble(((Double) pValueObject).doubleValue());
}
} else if (pValueObject instanceof Float) {
if (fByRef) {
targetVariant.putFloatRef(((Float) pValueObject).floatValue());
} else {
targetVariant.putFloat(((Float) pValueObject).floatValue());
}
} else if (pValueObject instanceof BigDecimal) {
if (fByRef) {
targetVariant.putDecimalRef(((BigDecimal) pValueObject));
} else {
targetVariant.putDecimal(((BigDecimal) pValueObject));
}
} else if (pValueObject instanceof Byte) {
if (fByRef) {
targetVariant.putByteRef(((Byte) pValueObject).byteValue());
} else {
targetVariant.putByte(((Byte) pValueObject).byteValue());
}
} else if (pValueObject instanceof Date) {
if (fByRef) {
targetVariant.putDateRef((Date) pValueObject);
} else {
targetVariant.putDate((Date) pValueObject);
}
} else if (pValueObject instanceof Long) {
if (fByRef) {
targetVariant.putLongRef(((Long) pValueObject).longValue());
} else {
targetVariant.putLong(((Long) pValueObject).longValue());
}
} else if (pValueObject instanceof Currency) {
if (fByRef) {
targetVariant.putCurrencyRef(((Currency) pValueObject));
} else {
targetVariant.putCurrency(((Currency) pValueObject));
}
} else if (pValueObject instanceof SafeArray) {
if (fByRef) {
targetVariant.putSafeArrayRef((SafeArray) pValueObject);
} else {
targetVariant.putSafeArray((SafeArray) pValueObject);
}
} else if (pValueObject instanceof Dispatch) {
if (fByRef) {
targetVariant.putDispatchRef((Dispatch) pValueObject);
} else {
targetVariant.putDispatch((Dispatch) pValueObject);
}
} else if (pValueObject instanceof Variant) {
// newly added 1.12-pre6 to support VT_VARIANT
targetVariant.putVariant(pValueObject);
} else {
// sourceforge patch 2171967
// used to rely on coercion but sometimes crashed VM
throw new NotImplementedException(
"populateVariant() not implemented for "
+ pValueObject.getClass());
}
}
/**
* Map arguments based on msdn documentation. This method relies on the
* variant constructor except for arrays.
*
* @param objectToBeMadeIntoVariant
* @return Variant that represents the object
*/
protected static Variant objectToVariant(Object objectToBeMadeIntoVariant) {
if (objectToBeMadeIntoVariant == null) {
return new Variant();
} else if (objectToBeMadeIntoVariant instanceof Variant) {
// if a variant was passed in then be a slacker and just return it
return (Variant) objectToBeMadeIntoVariant;
} else if (objectToBeMadeIntoVariant.getClass().isArray()) {
// automatically convert arrays using reflection
// handle it differently based on the type of array
// added primitive support sourceforge 2762275
SafeArray sa = null;
int len1 = Array.getLength(objectToBeMadeIntoVariant);
Class componentType = objectToBeMadeIntoVariant.getClass()
.getComponentType();
if (componentType.isArray()) { // array of arrays
int max = 0;
for (int i = 0; i < len1; i++) {
Object e1 = Array.get(objectToBeMadeIntoVariant, i);
int len2 = Array.getLength(e1);
if (max < len2) {
max = len2;
}
}
sa = new SafeArray(Variant.VariantVariant, len1, max);
for (int i = 0; i < len1; i++) {
Object e1 = Array.get(objectToBeMadeIntoVariant, i);
for (int j = 0; j < Array.getLength(e1); j++) {
sa.setVariant(i, j, objectToVariant(Array.get(e1, j)));
}
}
} else if (byte.class.equals(componentType)) {
byte[] arr = (byte[]) objectToBeMadeIntoVariant;
sa = new SafeArray(Variant.VariantByte, len1);
for (int i = 0; i < len1; i++) {
sa.setByte(i, arr[i]);
}
} else if (int.class.equals(componentType)) {
int[] arr = (int[]) objectToBeMadeIntoVariant;
sa = new SafeArray(Variant.VariantInt, len1);
for (int i = 0; i < len1; i++) {
sa.setInt(i, arr[i]);
}
} else if (double.class.equals(componentType)) {
double[] arr = (double[]) objectToBeMadeIntoVariant;
sa = new SafeArray(Variant.VariantDouble, len1);
for (int i = 0; i < len1; i++) {
sa.setDouble(i, arr[i]);
}
} else if (long.class.equals(componentType)) {
long[] arr = (long[]) objectToBeMadeIntoVariant;
sa = new SafeArray(Variant.VariantLongInt, len1);
for (int i = 0; i < len1; i++) {
sa.setLong(i, arr[i]);
}
} else {
// array of object
sa = new SafeArray(Variant.VariantVariant, len1);
for (int i = 0; i < len1; i++) {
sa.setVariant(i, objectToVariant(Array.get(
objectToBeMadeIntoVariant, i)));
}
}
Variant returnVariant = new Variant();
populateVariant(returnVariant, sa, false);
return returnVariant;
} else {
// rely on populateVariant to throw an exception if its an
// invalid type
Variant returnVariant = new Variant();
populateVariant(returnVariant, objectToBeMadeIntoVariant, false);
return returnVariant;
}
}
/**
* converts an array of objects into an array of Variants by repeatedly
* calling obj2Variant(Object)
*
* @param arrayOfObjectsToBeConverted
* @return Variant[]
*/
protected static Variant[] objectsToVariants(
Object[] arrayOfObjectsToBeConverted) {
Variant vArg[] = new Variant[arrayOfObjectsToBeConverted.length];
for (int i = 0; i < arrayOfObjectsToBeConverted.length; i++) {
vArg[i] = objectToVariant(arrayOfObjectsToBeConverted[i]);
}
return vArg;
}
/**
* Convert a JACOB Variant value to a Java object (type conversions).
* provided in Sourceforge feature request 959381. A fix was done to handle
* byRef bug report 1607878.
* <p>
* Unlike other toXXX() methods, it does not do a type conversion except for
* special data types (it shouldn't do any!)
* <p>
* Converts Variant.VariantArray types to SafeArrays
*
* @return Corresponding Java object of the type matching the Variant type.
* @throws IllegalStateException
* if no underlying windows data structure
* @throws NotImplementedException
* if unsupported conversion is requested
* @throws JacobException
* if the calculated result was a JacobObject usually as a
* result of error
*/
protected static Object variantToObject(Variant sourceData) {
Object result = null;
short type = sourceData.getvt(); // variant type
if ((type & Variant.VariantArray) == Variant.VariantArray) { // array
// returned?
SafeArray array = null;
type = (short) (type - Variant.VariantArray);
// From SF Bug 1840487
// This did call toSafeArray(false) but that meant
// this was the only variantToObject() that didn't have its own
// copy of the data so you would end up with weird run time
// errors after some GC. So now we just get stupid about it and
// always make a copy just like toSafeArray() does.
array = sourceData.toSafeArray();
result = array;
} else { // non-array object returned
switch (type) {
case Variant.VariantEmpty: // 0
case Variant.VariantNull: // 1
break;
case Variant.VariantShort: // 2
result = new Short(sourceData.getShort());
break;
case Variant.VariantShort | Variant.VariantByref: // 2
result = new Short(sourceData.getShortRef());
break;
case Variant.VariantInt: // 3
result = new Integer(sourceData.getInt());
break;
case Variant.VariantInt | Variant.VariantByref: // 3
result = new Integer(sourceData.getIntRef());
break;
case Variant.VariantFloat: // 4
result = new Float(sourceData.getFloat());
break;
case Variant.VariantFloat | Variant.VariantByref: // 4
result = new Float(sourceData.getFloatRef());
break;
case Variant.VariantDouble: // 5
result = new Double(sourceData.getDouble());
break;
case Variant.VariantDouble | Variant.VariantByref: // 5
result = new Double(sourceData.getDoubleRef());
break;
case Variant.VariantCurrency: // 6
result = sourceData.getCurrency();
break;
case Variant.VariantCurrency | Variant.VariantByref: // 6
result = sourceData.getCurrencyRef();
break;
case Variant.VariantDate: // 7
result = sourceData.getJavaDate();
break;
case Variant.VariantDate | Variant.VariantByref: // 7
result = sourceData.getJavaDateRef();
break;
case Variant.VariantString: // 8
result = sourceData.getString();
break;
case Variant.VariantString | Variant.VariantByref: // 8
result = sourceData.getStringRef();
break;
case Variant.VariantDispatch: // 9
result = sourceData.getDispatch();
break;
case Variant.VariantDispatch | Variant.VariantByref: // 9
result = sourceData.getDispatchRef(); // Can dispatches even
// be byRef?
break;
case Variant.VariantError: // 10
result = new NotImplementedException(
"toJavaObject() Not implemented for VariantError");
break;
case Variant.VariantBoolean: // 11
result = new Boolean(sourceData.getBoolean());
break;
case Variant.VariantBoolean | Variant.VariantByref: // 11
result = new Boolean(sourceData.getBooleanRef());
break;
case Variant.VariantVariant: // 12 they are always by ref
result = new NotImplementedException(
"toJavaObject() Not implemented for VariantVariant without ByRef");
break;
case Variant.VariantVariant | Variant.VariantByref: // 12
result = sourceData.getVariant();
break;
case Variant.VariantObject: // 13
result = new NotImplementedException(
"toJavaObject() Not implemented for VariantObject");
break;
case Variant.VariantDecimal: // 14
result = sourceData.getDecimal();
break;
case Variant.VariantDecimal | Variant.VariantByref: // 14
result = sourceData.getDecimalRef();
break;
case Variant.VariantByte: // 17
result = new Byte(sourceData.getByte());
break;
case Variant.VariantByte | Variant.VariantByref: // 17
result = new Byte(sourceData.getByteRef());
break;
case Variant.VariantLongInt: // 20
result = new Long(sourceData.getLong());
break;
case Variant.VariantLongInt | Variant.VariantByref: // 20
result = new Long(sourceData.getLongRef());
break;
case Variant.VariantTypeMask: // 4095
result = new NotImplementedException(
"toJavaObject() Not implemented for VariantTypeMask");
break;
case Variant.VariantArray: // 8192
result = new NotImplementedException(
"toJavaObject() Not implemented for VariantArray");
break;
case Variant.VariantByref: // 16384
result = new NotImplementedException(
"toJavaObject() Not implemented for VariantByref");
break;
default:
result = new NotImplementedException("Unknown return type: "
+ type);
// there was a "return result" here that caused defect 1602118
// so it was removed
break;
}// switch (type)
if (result instanceof JacobException) {
throw (JacobException) result;
}
}
return result;
}// toJava()
/**
* Verifies that we have a scale 0 <= x <= 28 and now more than 96 bits of
* data. The roundToMSDecimal method will attempt to adjust a BigDecimal to
* pass this set of tests
*
* @param in
* @throws IllegalArgumentException
* if out of bounds
*/
protected static void validateDecimalScaleAndBits(BigDecimal in) {
BigInteger allWordBigInt = in.unscaledValue();
if (in.scale() > 28) {
// should this cast to a string and call putStringRef()?
throw new IllegalArgumentException(
"VT_DECIMAL only supports a maximum scale of 28 and the passed"
+ " in value has a scale of " + in.scale());
} else if (in.scale() < 0) {
// should this cast to a string and call putStringRef()?
throw new IllegalArgumentException(
"VT_DECIMAL only supports a minimum scale of 0 and the passed"
+ " in value has a scale of " + in.scale());
} else if (allWordBigInt.bitLength() > 12 * 8) {
throw new IllegalArgumentException(
"VT_DECIMAL supports a maximum of "
+ 12
* 8
+ " bits not counting scale and the number passed in has "
+ allWordBigInt.bitLength());
} else {
// no bounds problem to be handled
}
}
/**
* Largest possible number with scale set to 0
*/
private static final BigDecimal LARGEST_DECIMAL = new BigDecimal(
new BigInteger("ffffffffffffffffffffffff", 16));
/**
* Smallest possible number with scale set to 0. MS doesn't support negative
* scales like BigDecimal.
*/
private static final BigDecimal SMALLEST_DECIMAL = new BigDecimal(
new BigInteger("ffffffffffffffffffffffff", 16).negate());
/**
* Does any validation that couldn't have been fixed by rounding or scale
* modification.
*
* @param in
* The BigDecimal to be validated
* @throws IllegalArgumentException
* if the number is too large or too small or null
*/
protected static void validateDecimalMinMax(BigDecimal in) {
if (in == null) {
throw new IllegalArgumentException(
"null is not a supported Decimal value.");
} else if (LARGEST_DECIMAL.compareTo(in) < 0) {
throw new IllegalArgumentException(
"Value too large for VT_DECIMAL data type:" + in.toString()
+ " integer: " + in.toBigInteger().toString(16)
+ " scale: " + in.scale());
} else if (SMALLEST_DECIMAL.compareTo(in) > 0) {
throw new IllegalArgumentException(
"Value too small for VT_DECIMAL data type:" + in.toString()
+ " integer: " + in.toBigInteger().toString(16)
+ " scale: " + in.scale());
}
}
/**
* Rounds the scale and bit length so that it will pass
* validateDecimalScaleBits(). Developers should call this method if they
* really want MS Decimal and don't want to lose precision.
* <p>
* Changing the scale on a number that can fit in an MS Decimal can change
* the number's representation enough that it will round to a number too
* large to be represented by an MS VT_DECIMAL
*
* @param sourceDecimal
* @return BigDecimal a new big decimal that was rounded to fit in an MS
* VT_DECIMAL
*/
public static BigDecimal roundToMSDecimal(BigDecimal sourceDecimal) {
BigInteger sourceDecimalIntComponent = sourceDecimal.unscaledValue();
BigDecimal destinationDecimal = new BigDecimal(
sourceDecimalIntComponent, sourceDecimal.scale());
int roundingModel = BigDecimal.ROUND_HALF_UP;
validateDecimalMinMax(destinationDecimal);
// First limit the number of digits and then the precision.
// Try and round to 29 digits because we can sometimes do that
BigInteger allWordBigInt;
allWordBigInt = destinationDecimal.unscaledValue();
if (allWordBigInt.bitLength() > 96) {
destinationDecimal = destinationDecimal.round(new MathContext(29));
// see if 29 digits uses more than 96 bits
if (allWordBigInt.bitLength() > 96) {
// Dang. It was over 97 bits so shorten it one more digit to
// stay <= 96 bits
destinationDecimal = destinationDecimal.round(new MathContext(
28));
}
}
// the bit manipulations above may change the scale so do it afterwards
// round the scale to the max MS can support
if (destinationDecimal.scale() > 28) {
destinationDecimal = destinationDecimal.setScale(28, roundingModel);
}
if (destinationDecimal.scale() < 0) {
destinationDecimal = destinationDecimal.setScale(0, roundingModel);
}
return destinationDecimal;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* a public class to variant that is used to track which variant objects are
* created by event callbacks This is solely used for that purpose.
*/
public class VariantViaEvent extends Variant {
/**
* Standard constructor used by JNI event handling layer
*/
public VariantViaEvent() {
super();
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
* All rights reserved. Originator: Dan Adler (http://danadler.com).
* Get more information about JACOB at http://sourceforge.net/projects/jacob-project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.jacob.com;
/**
* thrown in util.cpp
*/
public class WrongThreadException extends JacobException {
/**
* identifier generated by Eclipse
*/
private static final long serialVersionUID = 6308780364980228692L;
/**
* standard 0 arg constructor with no message
*
*/
public WrongThreadException() {
super("No Message Provided.");
}
/**
* standard constructor with a string message
*
* @param s
*/
public WrongThreadException(String s) {
super(s);
}
}