merged R-1_9 release tag against the root-B-1_9
This commit is contained in:
11
.cvsignore
Normal file
11
.cvsignore
Normal file
@@ -0,0 +1,11 @@
|
||||
jacob.dll
|
||||
jacob.jar
|
||||
jacobdll.jar
|
||||
*.zip
|
||||
RELEASE.txt
|
||||
.project
|
||||
.classpath
|
||||
compilation_tools.properties
|
||||
version.properties
|
||||
release
|
||||
|
||||
28
README.TXT
28
README.TXT
@@ -1,28 +0,0 @@
|
||||
For documentation see: http://users.rcn.com/danadler/jacob/
|
||||
|
||||
The java code is in com\jacob\*.
|
||||
|
||||
The C++ code is in .\jni.
|
||||
|
||||
To build, run:
|
||||
|
||||
nmake -f makefile
|
||||
|
||||
That will first compile the JAVA files and build the JAR file, and
|
||||
then compile the C++ code and build the DLL.
|
||||
|
||||
Building the jni:
|
||||
|
||||
The following are hardcoded into the makefile, so you may have to
|
||||
change it. I developed this with the C++ compiler and ATL version
|
||||
that ship with VC++ 6.0, so I'm not sure if different versions will
|
||||
work.
|
||||
|
||||
I have compiled this against JDK 1.1.6 and 1.2.2 as well as Microsoft
|
||||
SDK for Java 3.2 as the JDK setting.
|
||||
|
||||
DEST_DIR is a destination directory into which to copy the final DLL.
|
||||
|
||||
JDK = d:\j2sdk1.4.2_06
|
||||
DEST_DIR = d:\jacob
|
||||
MSDEVDIR = d:\apps\\"Microsoft Visual Studio"\VC98
|
||||
114
WhatsNew.html
114
WhatsNew.html
@@ -1,114 +0,0 @@
|
||||
<h1>What's New in JACOB 1.8</H1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<b>Move To SourceForge</b>
|
||||
The project is not housed at
|
||||
<a href="http://sourceforge.net/projects/jacob-project/">Sourceforge.net</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Licensing Change</b>
|
||||
All limitations on commercial use of JACOB have been removed and it
|
||||
is now being developed under a BSD license at
|
||||
<a href="http://sourceforge.net/projects/jacob-project/">Sourceforge.net</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Compiled with Java 1.4.2</b>
|
||||
Version 1.8 was compiled with JSEE 1.4.2 and fixes the compilation bug
|
||||
that was remnant of compilation with JDK 1.1.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Baseline For Change</b>
|
||||
This version is the baseline for the first CVS checkin and we encourage
|
||||
people to start contributing to the project with this version.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<h1>What's New in JACOB 1.7</H1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<b>Explicit COM Threading Model Support:</b>
|
||||
See a detailed discussion of
|
||||
<a href="JacobThreading.html">COM Apartments in JACOB</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>New COM Object Lifetime model:</b>
|
||||
See a detailed discussion of
|
||||
<a href="JacobComLifetime.html">COM Object Lifetime in JACOB</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Improved Event Handling:</b>
|
||||
Thanks to code contributed by
|
||||
<a href="mailto:n.o.bouvin@daimi.au.dk">
|
||||
Niels Olof Bouvin</a>
|
||||
and <a href="mailto:jehoej@daimi.au.dk">Henning Jae</a> JACOB 1.7 can
|
||||
read the type information of a Connection Point interface by looking
|
||||
it up in the registry. This makes it possible to use events with IE as
|
||||
well as office products.
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<b>Improved Dispatch:</b>
|
||||
Error messages from Invoke failures are now printed out as well as
|
||||
allowing the passing in of arguments to a Get method.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>EnumVariant Implementation:</b>
|
||||
Makes it easier to iterate over COM collections. Thanks to code
|
||||
contributed by
|
||||
<a href="mailto:Thomas.Hallgren@eoncompany.com">Thomas Hallgren</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>SafeArray leaks:</b>
|
||||
SafeArrays were not being properly freed prior to version 1.7, many
|
||||
other memory leaks were fixed as well.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Visual Studio Project:</b>
|
||||
For those who want to debug: vstudio/jacob. At the moment all the
|
||||
native code is replicated there from the jni directory...
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<H1>Related Links</H1>
|
||||
<ul>
|
||||
<li>
|
||||
The JACOB mailing list is hosted at yahoo groups:
|
||||
<a href="http://groups.yahoo.com/group/jacob-project">
|
||||
http://groups.yahoo.com/group/jacob-project</a>.
|
||||
<b>This is the preferred way to get support for JACOB</b>. It also
|
||||
includes an extensive archive. If you are doing any development with
|
||||
JACOB, please join the list.
|
||||
<li>
|
||||
Massimiliano Bigatti has developed
|
||||
<a href="http://www.bigatti.it/projects/jacobgen/">
|
||||
Jacobgen - a generator that automatically creates JACOB code from
|
||||
Type Libraries</a>
|
||||
</li>
|
||||
<li>
|
||||
Steven Lewis is developing a version of Java2Com that supports JACOB
|
||||
code generation. See:
|
||||
<a href="http://www.lordjoe.com/Java2Com/index.html">
|
||||
http://www.lordjoe.com/Java2Com/index.html</a>.
|
||||
<li>
|
||||
To find documentation on the com.ms.com package, go to:
|
||||
<a href="http://www.microsoft.com/java/download/dl_sdk40.htm">
|
||||
http://www.microsoft.com/java/download/dl_sdk40.htm</a>
|
||||
and at the bottom of the page is a link that says:
|
||||
Microsoft SDK for Java 4.0 Documentation Only. You should download
|
||||
that file and install it. Then, view sdkdocs.chm and look for
|
||||
"Microsoft Packages Reference". Hopefully, the next release of
|
||||
JACOB will include full javadoc (volunteers?)...
|
||||
</li>
|
||||
267
build.xml
Normal file
267
build.xml
Normal file
@@ -0,0 +1,267 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- ======================================================================
|
||||
Feb 4, 2005 1:23:05 PM
|
||||
|
||||
Ant build file for JACOB.
|
||||
Tested on Eclipse 3.0.0 and Ant 1.6.1, with MS Visual C++ 6.0
|
||||
|
||||
Eclipse users are pretty lucky. This works with the version of ANT
|
||||
that comes with Eclipse 3.0.1 (maybe 3.0.0). The whole project
|
||||
can be built inside eclipse.
|
||||
|
||||
If you do not have a C++ environment check out the following sites
|
||||
http://msdn.microsoft.com/visualc/vctoolkit2003/
|
||||
http://www.eclipse.org/cdt/
|
||||
http://eclipsewiki.editme.com/InstallingCDTWithMSVisualC
|
||||
|
||||
====================================================================== -->
|
||||
<project name="jacob" default="default" basedir=".">
|
||||
<property file="compilation_tools.properties" />
|
||||
<!-- =v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=v=
|
||||
YOU MUST define a file named compilation_tools.properties
|
||||
and looking like this:
|
||||
|
||||
JDK=D:/J2SDK-1_4_2
|
||||
MSDEVDIR=C:/Program Files/Microsoft Visual Studio/VC98
|
||||
version=1.9
|
||||
|
||||
DO NOT check this file into source control as the values are specific
|
||||
to YOUR environment.
|
||||
|
||||
the version.properties file is now completely autogenerated
|
||||
|
||||
=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^=^ -->
|
||||
|
||||
<property name="application.title" value="JACOB : Java COM Bridge" />
|
||||
<property name="application.vendor" value="http://jacob-project.sourceforge.net, created by Dan Adler (http://danadler.com)" />
|
||||
<property name="install.dir" value="${basedir}/release" />
|
||||
|
||||
<property name="jacob_java.src" value="${basedir}/src" />
|
||||
<property name="jacob_java.samples" value="${basedir}/samples" />
|
||||
<property name="jacob_java.unittest" value="${basedir}/unittest" />
|
||||
<property name="jacob_java.bin" value="${install.dir}" />
|
||||
<property name="jacob_cpp.src" value="${basedir}/jni" />
|
||||
<property name="jacob_cpp.bin" value="${install.dir}/jni" />
|
||||
|
||||
<property name="jacob.jar" value="${install.dir}/jacob.jar" />
|
||||
<property name="jacob.dll" value="${install.dir}/jacob.dll" />
|
||||
|
||||
<property name="compiler" value="${MSDEVDIR}\bin\cl.exe" />
|
||||
<property name="linker" value="${MSDEVDIR}\bin\link.exe" />
|
||||
|
||||
<!-- =================================
|
||||
target: default
|
||||
================================= -->
|
||||
<target name="default" depends="createDirectoryStructure,jacob_java_jar_bin,jacob_c_dll">
|
||||
|
||||
<echo message="Jacob ${version} build ${build.iteration} : finished on ${build.date}" />
|
||||
</target>
|
||||
|
||||
<!-- ======================================================================
|
||||
Writes out a version file to be included in the jar
|
||||
================================================================== -->
|
||||
<target name="IncrementBuildNumber">
|
||||
<propertyfile file="version.properties">
|
||||
<entry key="version" type="string" value="${version}" />
|
||||
<entry key="build.iteration" type="int" operation="+" value="1" pattern="00" />
|
||||
<entry key="build.date" type="date" value="now" operation="=" pattern="dd-MMMM-yyyy HH:mm:ss" />
|
||||
</propertyfile>
|
||||
<property file="version.properties" />
|
||||
</target>
|
||||
|
||||
<!-- ======================================================================
|
||||
Create the necessary directory structure (does nothing if it
|
||||
already there)
|
||||
================================================================== -->
|
||||
<target name="createDirectoryStructure">
|
||||
<mkdir dir="${jacob_java.bin}"/>
|
||||
<mkdir dir="${jacob_cpp.bin}"/>
|
||||
<mkdir dir="${install.dir}"/>
|
||||
</target>
|
||||
|
||||
<!-- ======================================================================
|
||||
Compare the date/time of the jacob JAR against that
|
||||
of the jacob java source
|
||||
================================================================== -->
|
||||
<target name="jacob_java_jar_check">
|
||||
<uptodate property="jarUpToDate" targetfile="${jacob.jar}">
|
||||
<srcfiles dir="${jacob_java.src}">
|
||||
<include name="com/**/*.java" />
|
||||
</srcfiles>
|
||||
<!-- Check the build file itself as well -->
|
||||
<srcfiles file="${basedir}/build.xml" />
|
||||
</uptodate>
|
||||
<echo message="jacob_java_jar_check result: ${jarUpToDate}" />
|
||||
</target>
|
||||
<!-- ======================================================================
|
||||
Compile the java files
|
||||
Relies on ant recognizing when a file needs to be compiled
|
||||
================================================================== -->
|
||||
<target name="jacob_java_compile" depends="createDirectoryStructure,IncrementBuildNumber">
|
||||
<echo>Building java classes...</echo>
|
||||
<javac srcdir="${jacob_java.src}"
|
||||
destdir="${jacob_java.bin}"
|
||||
listfiles="true" debug="on" fork="yes" />
|
||||
<echo>Building java sample classes...</echo>
|
||||
<javac srcdir="${jacob_java.samples}"
|
||||
destdir="${jacob_java.bin}"
|
||||
excludes="com/jacob/samples/servlet/**/*.java"
|
||||
listfiles="true" debug="on" fork="yes" />
|
||||
<echo>Building java test classes...</echo>
|
||||
<javac srcdir="${jacob_java.unittest}"
|
||||
destdir="${jacob_java.bin}"
|
||||
listfiles="true" debug="on" fork="yes" />
|
||||
</target>
|
||||
<!-- ======================================================================
|
||||
Package the classes into a JAR.
|
||||
Put version.propertes into the jar file so getJacobVersion() can find it
|
||||
================================================================== -->
|
||||
<target name="jacob_java_jar_bin" depends="createDirectoryStructure,jacob_java_compile,jacob_java_jar_check,IncrementBuildNumber" unless="jarUpToDate">
|
||||
<echo>Removing old jars</echo>
|
||||
<delete file="${jacob.jar}" />
|
||||
<echo>Packaging java classes...</echo>
|
||||
<jar destfile="${jacob.jar}" basedir="${jacob_java.bin}" update="false">
|
||||
<exclude name="**/CVS" />
|
||||
<exclude name="com/**/*Test.class"/>
|
||||
<exclude name="com/jacob/samples/**"/>
|
||||
<include name="com/**/*.class" />
|
||||
<include name="version.properties" />
|
||||
<manifest>
|
||||
<attribute name="Built-By" value="${user.name}" />
|
||||
<section name="com.jacob">
|
||||
<attribute name="Specification-Title" value="${application.title}" />
|
||||
<attribute name="Specification-Vendor" value="${application.vendor}" />
|
||||
<attribute name="Implementation-Title" value="${application.title} Java libraries" />
|
||||
<attribute name="Implementation-Version" value="${version} build ${build.iteration} on ${build.date}" />
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<!-- ======================================================================
|
||||
Compare the date/time of the jacob DLL against that
|
||||
of the jacob cpp source
|
||||
================================================================== -->
|
||||
<target name="jacob_c_check">
|
||||
<uptodate property="dllUpToDate" targetfile="${jacob.dll}">
|
||||
<srcfiles dir="${jacob_cpp.src}">
|
||||
<include name="*.cpp" />
|
||||
<include name="*.h" />
|
||||
</srcfiles>
|
||||
<!-- Check the build file itself as well -->
|
||||
<srcfiles file="${basedir}/build.xml" />
|
||||
</uptodate>
|
||||
<echo message="jacob_c_check result: ${dllUpToDate}" />
|
||||
</target>
|
||||
<!-- ======================================================================
|
||||
Compile the c source files.
|
||||
================================================================== -->
|
||||
<target name="jacob_c_compile" depends="createDirectoryStructure,jacob_c_check,IncrementBuildNumber" unless="dllUpToDate">
|
||||
<echo>Clean up the target folders and file, for safety</echo>
|
||||
<delete file="${jacob_cpp.bin}/**/*.*" />
|
||||
<echo>Compiling C++ classes</echo>
|
||||
<apply executable="${compiler}" dir="${jacob_cpp.bin}" parallel="false" verbose="true" failonerror="true">
|
||||
<arg value="-c" />
|
||||
<arg value="/nologo" />
|
||||
<!-- optimize build for speed. (is this VC specific? -->
|
||||
<arg value="/O2" />
|
||||
<arg value="-I" />
|
||||
<arg value="${JDK}\include" />
|
||||
<arg value="-I" />
|
||||
<arg value="${JDK}\include\win32" />
|
||||
<arg value="-I" />
|
||||
<arg value="${MSDEVDIR}\Include" />
|
||||
<arg value="-I" />
|
||||
<arg value="${MSDEVDIR}\ATL\Include" />
|
||||
<fileset dir="${jacob_cpp.src}">
|
||||
<include name="*.cpp" />
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
<!-- ======================================================================
|
||||
Link the obj files into a DLL.
|
||||
================================================================== -->
|
||||
<target name="jacob_c_dll" depends="createDirectoryStructure,jacob_c_check,jacob_c_compile" unless="dllUpToDate">
|
||||
<echo>Clean up the target folders and file, for safety</echo>
|
||||
<delete file="${jacob.dll}" />
|
||||
<echo>Creating jacob.dll</echo>
|
||||
<apply executable="${linker}" dir="${jacob_cpp.bin}" parallel="true" verbose="true" failonerror="true">
|
||||
<arg value="/nologo" />
|
||||
<arg value="/dll" />
|
||||
<arg value="/version:${version}" />
|
||||
<arg value="/out:${jacob.dll}" />
|
||||
<arg value="/libpath:${MSDEVDIR}/lib" />
|
||||
<srcfile />
|
||||
<arg value="${JDK}\lib\jvm.lib" />
|
||||
<arg value="oleaut32.lib" />
|
||||
<arg value="ole32.lib" />
|
||||
<arg value="uuid.lib" />
|
||||
<arg value="kernel32.lib" />
|
||||
<arg value="shell32.lib" />
|
||||
<arg value="user32.lib" />
|
||||
<fileset dir="${jacob_cpp.bin}">
|
||||
<include name="*.obj" />
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- ======================================================================
|
||||
Use this target to create javadoc from com.jacob.*
|
||||
================================================================== -->
|
||||
<target name="javadoc">
|
||||
<defaultexcludes add="**/*Test*"/>
|
||||
<javadoc
|
||||
packagenames="com.jacob/**"
|
||||
sourcepath="${jacob_java.src}"
|
||||
destdir="${jacob_java.bin}/docs/api"
|
||||
author="true"
|
||||
version="true"
|
||||
use="true"
|
||||
windowtitle="Jacob API Docs">
|
||||
|
||||
<doctitle><![CDATA[<h1>Java Com Bridge (Jacob)</h1>]]></doctitle>
|
||||
<bottom><![CDATA[<i>See Jacob-project on Sourceforge for more info</i>]]></bottom>
|
||||
<tag name="todo" scope="all" description="To do:" />
|
||||
<group title="Jacob COM" packages="com.jacob.com/**"/>
|
||||
<group title="Higher Level Active X" packages="com.jacob.activeX/**"/>
|
||||
<link offline="true" href="http://java.sun.com/j2se/1.4.2/docs/api/" packagelistLoc="C:\tmp"/>
|
||||
<link href="http://java.sun.com/j2se/1.4.2/docs/api/"/>
|
||||
</javadoc>
|
||||
<defaultexcludes default="true"/>
|
||||
</target>
|
||||
|
||||
<!-- ======================================================================
|
||||
Use this target to package all the files for a release
|
||||
================================================================== -->
|
||||
<target name="PackageRelease" depends="createDirectoryStructure,jacob_c_dll,jacob_java_jar_bin,javadoc">
|
||||
|
||||
<echo>Packaging release...</echo>
|
||||
<zip
|
||||
destfile="${install.dir}/jacob_${version}.zip">
|
||||
<exclude name="**/CVS" />
|
||||
<exclude name="**/*.obj" />
|
||||
<exclude name="**/*.class" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="LICENSE.* version.properties" />
|
||||
<zipfileset dir="${install.dir}" prefix="jacob_${version}" includes="jacob.jar jacob.dll"/>
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="docs/**" />
|
||||
<zipfileset dir="${install.dir}" prefix="jacob_${version}" includes="docs/**"/>
|
||||
</zip>
|
||||
<zip
|
||||
destfile="${install.dir}/jacob_${version}_src.zip">
|
||||
<exclude name="**/CVS" />
|
||||
<exclude name="**/*.obj" />
|
||||
<exclude name="**/*.class" />
|
||||
<exclude name="**/*.dll" />
|
||||
<exclude name="**/*.exp" />
|
||||
<exclude name="**/*.jar" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="src/**" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="docs/**" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="jni/**" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="samples/**" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="unittest/**" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="vstudio/**" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="build.xml, RELEASE.txt" />
|
||||
<zipfileset dir="${basedir}" prefix="jacob_${version}" includes="LICENSE.* version.properties" />
|
||||
</zip>
|
||||
</target>
|
||||
</project>
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
|
||||
* All rights reserved. Originator: Dan Adler (http://danadler.com).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Redistributions in any form must be accompanied by information on
|
||||
* how to obtain complete source code for the JACOB software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jacob.activeX;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
/**
|
||||
* This class simulates com.ms.activeX.ActiveXComponent only as it used for
|
||||
* creating Dispatch objects
|
||||
*/
|
||||
public class ActiveXComponent extends Dispatch {
|
||||
/**
|
||||
* @param progid
|
||||
*/
|
||||
public ActiveXComponent(String progid) {
|
||||
super(progid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return actually returns this bject
|
||||
*/
|
||||
public Object getObject() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param args
|
||||
* @return Variant result of the invoke
|
||||
*/
|
||||
public Variant invoke(String name, Variant[] args) {
|
||||
return Dispatch.callN(this, name, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name property name
|
||||
* @return Variant value of property
|
||||
*/
|
||||
public Variant getProperty(String name) {
|
||||
return Dispatch.get(this, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param arg
|
||||
*/
|
||||
public void setProperty(String name, Variant arg) {
|
||||
Dispatch.put(this, name, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see com.jacob.com.Dispatch#finalize()
|
||||
*/
|
||||
protected void finalize() {
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("jacob");
|
||||
}
|
||||
}
|
||||
@@ -1,589 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
|
||||
* All rights reserved. Originator: Dan Adler (http://danadler.com).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Redistributions in any form must be accompanied by information on
|
||||
* how to obtain complete source code for the JACOB software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jacob.com;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/**
|
||||
* Object represents MS level dispatch object. You're going to live here
|
||||
* a lot
|
||||
*/
|
||||
public class Dispatch extends JacobObject
|
||||
{
|
||||
/**
|
||||
* This is public because Dispatch.cpp knows its name and accesses
|
||||
* it directly to get the disptach id. You really can't rename
|
||||
* it or make it private
|
||||
*/
|
||||
public int m_pDispatch;
|
||||
/** program Id passed in by ActiveX components in their constructor */
|
||||
private String programId = null;
|
||||
|
||||
public static final int LOCALE_SYSTEM_DEFAULT = 2048;
|
||||
public static final int Method = 1;
|
||||
public static final int Get = 2;
|
||||
public static final int Put = 4;
|
||||
public static final int PutRef = 8;
|
||||
public static final int fdexNameCaseSensitive = 1;
|
||||
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;
|
||||
|
||||
|
||||
// map args based on msdn doc
|
||||
protected static Variant obj2variant(Object o) {
|
||||
if (o == null)
|
||||
return new Variant();
|
||||
if (o instanceof Variant)
|
||||
return (Variant) o;
|
||||
if (o instanceof Integer)
|
||||
return new Variant(((Integer) o).intValue());
|
||||
if (o instanceof String)
|
||||
return new Variant((String) o);
|
||||
if (o instanceof Boolean)
|
||||
return new Variant(((Boolean) o).booleanValue());
|
||||
if (o instanceof Double)
|
||||
return new Variant(((Double) o).doubleValue());
|
||||
if (o instanceof Float)
|
||||
return new Variant(((Float) o).floatValue());
|
||||
if (o instanceof SafeArray)
|
||||
return new Variant((SafeArray) o);
|
||||
if (o instanceof Dispatch) {
|
||||
Variant v = new Variant();
|
||||
v.putObject((Dispatch) o);
|
||||
return v;
|
||||
}
|
||||
// automatically convert arrays using reflection
|
||||
Class c1 = o.getClass();
|
||||
SafeArray sa = null;
|
||||
if (c1.isArray()) {
|
||||
int len1 = Array.getLength(o);
|
||||
Object first = Array.get(o, 0);
|
||||
if (first.getClass().isArray()) {
|
||||
int max = 0;
|
||||
for (int i = 0; i < len1; i++) {
|
||||
Object e1 = Array.get(o, 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(o, i);
|
||||
for (int j = 0; j < Array.getLength(e1); j++) {
|
||||
sa.setVariant(i, j, obj2variant(Array.get(e1, j)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sa = new SafeArray(Variant.VariantVariant, len1);
|
||||
for (int i = 0; i < len1; i++) {
|
||||
sa.setVariant(i, obj2variant(Array.get(o, i)));
|
||||
}
|
||||
}
|
||||
return new Variant(sa);
|
||||
}
|
||||
throw new ClassCastException("cannot convert to Variant");
|
||||
}
|
||||
|
||||
/**
|
||||
* same as above, for an array
|
||||
* @param o
|
||||
* @return Variant[]
|
||||
*/
|
||||
protected static Variant[] obj2variant(Object[] o) {
|
||||
Variant vArg[] = new Variant[o.length];
|
||||
for (int i = 0; i < o.length; i++) {
|
||||
vArg[i] = obj2variant(o[i]);
|
||||
}
|
||||
return vArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* zero argument constructor that sets the dispatch pointer to 0
|
||||
*/
|
||||
public Dispatch() {
|
||||
m_pDispatch = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that calls createInstance with progid. This is the
|
||||
* constructor used by the ActiveXComponent
|
||||
*
|
||||
* @param requestedProgramId
|
||||
*/
|
||||
public Dispatch(String requestedProgramId) {
|
||||
programId = requestedProgramId;
|
||||
createInstance(requestedProgramId);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a different interface by IID string
|
||||
*
|
||||
* @param iid
|
||||
* @return Dispatch a disptach that matches ??
|
||||
*/
|
||||
public native Dispatch QueryInterface(String iid);
|
||||
|
||||
/**
|
||||
* Constructor that only gets called from JNI
|
||||
*
|
||||
* @param pDisp
|
||||
*/
|
||||
protected Dispatch(int pDisp) {
|
||||
m_pDispatch = pDisp;
|
||||
}
|
||||
|
||||
/**
|
||||
* native call createIstnace only used by the constructor with the same parm
|
||||
* type could this be private?
|
||||
*
|
||||
* @param progid
|
||||
*/
|
||||
protected native void createInstance(String progid);
|
||||
|
||||
/**
|
||||
* returns the program id if an activeX component created this
|
||||
* otherwise it returns null. This was added to aid in debugging
|
||||
* @return the program id an activeX component was created against
|
||||
*/
|
||||
public String getProgramId(){
|
||||
return programId;
|
||||
}
|
||||
|
||||
/**
|
||||
* call this to explicitly release the com object before gc
|
||||
*/
|
||||
public native void release();
|
||||
|
||||
/**
|
||||
* not implemented yet
|
||||
*
|
||||
* @param disp
|
||||
* @param name
|
||||
* @param val
|
||||
* @throws ClassCastException
|
||||
* because???
|
||||
*/
|
||||
public static void put_Casesensitive(Object disp, String name, Object val) {
|
||||
throw new ClassCastException("not implemented yet");
|
||||
}
|
||||
|
||||
// eliminate _Guid arg
|
||||
public static void invokeSubv(Object disp, String name, int dispID,
|
||||
int lcid, int wFlags, Variant[] vArg, int[] uArgErr) {
|
||||
invokev(disp, name, dispID, lcid, wFlags, vArg, uArgErr);
|
||||
}
|
||||
|
||||
public static void invokeSubv(Object disp, String name, int wFlags,
|
||||
Variant[] vArg, int[] uArgErr) {
|
||||
invokev(disp, name, 0, LOCALE_SYSTEM_DEFAULT, wFlags, vArg, uArgErr);
|
||||
}
|
||||
|
||||
public static void invokeSubv(Object disp, int dispID, int wFlags,
|
||||
Variant[] vArg, int[] uArgErr) {
|
||||
invokev(disp, null, dispID, LOCALE_SYSTEM_DEFAULT, wFlags, vArg,
|
||||
uArgErr);
|
||||
}
|
||||
|
||||
public static Variant callN_CaseSensitive(Object disp, String name,
|
||||
Object[] values) {
|
||||
throw new ClassCastException("not implemented yet");
|
||||
}
|
||||
|
||||
public static void callSubN(Object disp, String name, Object[] args) {
|
||||
invokeSubv(disp, name, Method | Get, obj2variant(args),
|
||||
new int[args.length]);
|
||||
}
|
||||
|
||||
public static void callSubN(Object disp, int dispID, Object[] args) {
|
||||
invokeSubv(disp, dispID, Method | Get, obj2variant(args),
|
||||
new int[args.length]);
|
||||
}
|
||||
|
||||
public static int getIDOfName(Object disp, String name) {
|
||||
int ids[] = getIDsOfNames(disp, LOCALE_SYSTEM_DEFAULT,
|
||||
new String[] { name });
|
||||
return ids[0];
|
||||
}
|
||||
|
||||
// eliminated _Guid argument
|
||||
public static native int[] getIDsOfNames(Object disp, int lcid,
|
||||
String[] names);
|
||||
|
||||
// eliminated _Guid argument
|
||||
public static int[] getIDsOfNames(Object disp, String[] names) {
|
||||
return getIDsOfNames(disp, LOCALE_SYSTEM_DEFAULT, names);
|
||||
}
|
||||
|
||||
public static Variant callN(Object disp, String name, Object[] args) {
|
||||
return invokev(disp, name, Method | Get, obj2variant(args),
|
||||
new int[args.length]);
|
||||
}
|
||||
|
||||
public static Variant callN(Object disp, int dispID, Object[] args) {
|
||||
return invokev(disp, dispID, Method | Get, obj2variant(args),
|
||||
new int[args.length]);
|
||||
}
|
||||
|
||||
public static Variant invoke(Object disp, String name, int dispID,
|
||||
int lcid, int wFlags, Object[] oArg, int[] uArgErr) {
|
||||
return invokev(disp, name, dispID, lcid, wFlags, obj2variant(oArg),
|
||||
uArgErr);
|
||||
}
|
||||
|
||||
public static Variant invoke(Object disp, String name, int wFlags,
|
||||
Object[] oArg, int[] uArgErr) {
|
||||
return invokev(disp, name, wFlags, obj2variant(oArg), uArgErr);
|
||||
}
|
||||
|
||||
public static Variant invoke(Object disp, int dispID, int wFlags,
|
||||
Object[] oArg, int[] uArgErr) {
|
||||
return invokev(disp, dispID, wFlags, obj2variant(oArg), uArgErr);
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name) {
|
||||
return callN(disp, name, new Variant[0]);
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1) {
|
||||
return callN(disp, name, new Object[] { a1 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2) {
|
||||
return callN(disp, name, new Object[] { a1, a2 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2,
|
||||
Object a3) {
|
||||
return callN(disp, name, new Object[] { a1, a2, a3 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4) {
|
||||
return callN(disp, name, new Object[] { a1, a2, a3, a4 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5) {
|
||||
return callN(disp, name, new Object[] { a1, a2, a3, a4, a5 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6) {
|
||||
return callN(disp, name, new Object[] { a1, a2, a3, a4, a5, a6 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7) {
|
||||
return callN(disp, name, new Object[] { a1, a2, a3, a4, a5, a6, a7 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) {
|
||||
return callN(disp, name,
|
||||
new Object[] { a1, a2, a3, a4, a5, a6, a7, a8 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid) {
|
||||
return callN(disp, dispid, new Variant[0]);
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1) {
|
||||
return callN(disp, dispid, new Object[] { a1 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2, a3 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2, a3, a4 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2, a3, a4, a5 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2, a3, a4, a5, a6 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2, a3, a4, a5, a6, a7 });
|
||||
}
|
||||
|
||||
public static Variant call(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) {
|
||||
return callN(disp, dispid, new Object[] { a1, a2, a3, a4, a5, a6, a7,
|
||||
a8 });
|
||||
}
|
||||
|
||||
public static void put(Object disp, String name, Object val) {
|
||||
invoke(disp, name, Put, new Object[] { val }, new int[1]);
|
||||
}
|
||||
|
||||
public static void put(Object disp, int dispid, Object val) {
|
||||
invoke(disp, dispid, Put, new Object[] { val }, new int[1]);
|
||||
}
|
||||
|
||||
// removed _Guid argument
|
||||
public static native Variant invokev(Object disp, String name, int dispID,
|
||||
int lcid, int wFlags, Variant[] vArg, int[] uArgErr);
|
||||
|
||||
public static Variant invokev(Object disp, String name, int wFlags,
|
||||
Variant[] vArg, int[] uArgErr) {
|
||||
if (!(disp instanceof Dispatch))
|
||||
throw new ClassCastException("Dispatch object expected");
|
||||
return invokev(disp, name, 0, LOCALE_SYSTEM_DEFAULT, wFlags, vArg,
|
||||
uArgErr);
|
||||
}
|
||||
|
||||
public static Variant invokev(Object disp, String name, int wFlags,
|
||||
Variant[] vArg, int[] uArgErr, int wFlagsEx) {
|
||||
if (!(disp instanceof Dispatch))
|
||||
throw new ClassCastException("Dispatch object expected");
|
||||
// do not implement IDispatchEx for now
|
||||
return invokev(disp, name, 0, LOCALE_SYSTEM_DEFAULT, wFlags, vArg,
|
||||
uArgErr);
|
||||
}
|
||||
|
||||
public static Variant invokev(Object disp, int dispID, int wFlags,
|
||||
Variant[] vArg, int[] uArgErr) {
|
||||
if (!(disp instanceof Dispatch))
|
||||
throw new ClassCastException("Dispatch object expected");
|
||||
return invokev(disp, null, dispID, LOCALE_SYSTEM_DEFAULT, wFlags, vArg,
|
||||
uArgErr);
|
||||
}
|
||||
|
||||
// removed _Guid argument
|
||||
public static void invokeSub(Object disp, String name, int dispid,
|
||||
int lcid, int wFlags, Object[] oArg, int[] uArgErr) {
|
||||
invokeSubv(disp, name, dispid, lcid, wFlags, obj2variant(oArg), uArgErr);
|
||||
}
|
||||
|
||||
public static void invokeSub(Object disp, String name, int wFlags,
|
||||
Object[] oArg, int[] uArgErr) {
|
||||
invokeSub(disp, name, 0, LOCALE_SYSTEM_DEFAULT, wFlags, oArg, uArgErr);
|
||||
}
|
||||
|
||||
public static void invokeSub(Object disp, int dispid, int wFlags,
|
||||
Object[] oArg, int[] uArgErr) {
|
||||
invokeSub(disp, null, dispid, LOCALE_SYSTEM_DEFAULT, wFlags, oArg,
|
||||
uArgErr);
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name) {
|
||||
callSubN(disp, name, new Object[0]);
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1) {
|
||||
callSubN(disp, name, new Object[] { a1 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2) {
|
||||
callSubN(disp, name, new Object[] { a1, a2 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2,
|
||||
Object a3) {
|
||||
callSubN(disp, name, new Object[] { a1, a2, a3 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4) {
|
||||
callSubN(disp, name, new Object[] { a1, a2, a3, a4 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5) {
|
||||
callSubN(disp, name, new Object[] { a1, a2, a3, a4, a5 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6) {
|
||||
callSubN(disp, name, new Object[] { a1, a2, a3, a4, a5, a6 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7) {
|
||||
callSubN(disp, name, new Object[] { a1, a2, a3, a4, a5, a6, a7 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, String name, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) {
|
||||
callSubN(disp, name, new Object[] { a1, a2, a3, a4, a5, a6, a7, a8 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid) {
|
||||
callSubN(disp, dispid, new Object[0]);
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1) {
|
||||
callSubN(disp, dispid, new Object[] { a1 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2, a3 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2, a3, a4 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2, a3, a4, a5 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2, a3, a4, a5, a6 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2, a3, a4, a5, a6, a7 });
|
||||
}
|
||||
|
||||
public static void callSub(Object disp, int dispid, Object a1, Object a2,
|
||||
Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) {
|
||||
callSubN(disp, dispid, new Object[] { a1, a2, a3, a4, a5, a6, a7, a8 });
|
||||
}
|
||||
|
||||
public static Variant get(Object disp, String name) {
|
||||
return invokev(disp, name, Get, new Variant[0], new int[0]);
|
||||
}
|
||||
|
||||
public static Variant get(Object disp, int dispid) {
|
||||
return invokev(disp, dispid, Get, new Variant[0], new int[0]);
|
||||
}
|
||||
|
||||
public static void putRef(Object disp, String name, Object val) {
|
||||
invoke(disp, name, PutRef, new Object[] { val }, new int[1]);
|
||||
}
|
||||
|
||||
public static void putRef(Object disp, int dispid, Object val) {
|
||||
invoke(disp, dispid, PutRef, new Object[] { val }, new int[1]);
|
||||
}
|
||||
|
||||
public static Variant get_CaseSensitive(Object disp, String name) {
|
||||
throw new ClassCastException("not implemented yet");
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("jacob");
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
//System.out.println("Dispatch finalize start");
|
||||
if (m_pDispatch != 0)
|
||||
release();
|
||||
//System.out.println("Dispatch finalize end");
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
|
||||
* All rights reserved. Originator: Dan Adler (http://danadler.com).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Redistributions in any form must be accompanied by information on
|
||||
* how to obtain complete source code for the JACOB software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jacob.com;
|
||||
|
||||
/**
|
||||
* ???
|
||||
*/
|
||||
public class DispatchEvents extends JacobObject {
|
||||
int m_pConnPtProxy = 0;
|
||||
|
||||
/**
|
||||
* @param src
|
||||
* @param sink
|
||||
*/
|
||||
public DispatchEvents(Dispatch src, Object sink) {
|
||||
init(src, sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param src
|
||||
* @param sink
|
||||
* @param progId
|
||||
*/
|
||||
public DispatchEvents(Dispatch src, Object sink, String progId) {
|
||||
init2(src, sink, progId);
|
||||
}
|
||||
|
||||
// hook up a connection point proxy object
|
||||
// event methods on the sink object will be called
|
||||
// by name with a signature of <name>(Variant[] args)
|
||||
protected native void init(Dispatch src, Object sink);
|
||||
|
||||
protected native void init2(Dispatch src, Object sink, String progId);
|
||||
|
||||
// call this to explicitly release the com object before gc
|
||||
public native void release();
|
||||
|
||||
protected void finalize() {
|
||||
//System.out.println("DispatchEvents finalize start");
|
||||
if (m_pConnPtProxy != 0)
|
||||
release();
|
||||
//System.out.println("DispatchEvents finalize end");
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("jacob");
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
|
||||
* All rights reserved. Originator: Dan Adler (http://danadler.com).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Redistributions in any form must be accompanied by information on
|
||||
* how to obtain complete source code for the JACOB software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jacob.com;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public JacobObject() {
|
||||
ROT.addObject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void release() {
|
||||
// currently does nothing
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
|
||||
* All rights reserved. Originator: Dan Adler (http://danadler.com).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Redistributions in any form must be accompanied by information on
|
||||
* how to obtain complete source code for the JACOB software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jacob.com;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* The Running Object Table (ROT) maps each thread to a vector 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. Conceptually, this is similar to the ThreadLocal class of
|
||||
* Java 1.2 but we are also supporting Java 1.6 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. If we leave this job to the garbage
|
||||
* collector, then finalize might get called from a separate thread which is not
|
||||
* initialized for COM, and also the component itself may have been freed.
|
||||
*/
|
||||
public abstract class ROT {
|
||||
private static Hashtable rot = new Hashtable();
|
||||
|
||||
protected static void addThread() {
|
||||
String t_name = Thread.currentThread().getName();
|
||||
if (rot.contains(t_name))
|
||||
return;
|
||||
Vector v = new Vector();
|
||||
rot.put(t_name, v);
|
||||
}
|
||||
|
||||
protected static void clearObjects() {
|
||||
String t_name = Thread.currentThread().getName();
|
||||
Vector v = (Vector) rot.get(t_name);
|
||||
if (v != null) {
|
||||
while (!v.isEmpty()) {
|
||||
JacobObject o = (JacobObject) v.elementAt(0);
|
||||
//System.out.println(t_name + "
|
||||
// release:"+o+"->"+o.getClass().getName());
|
||||
if (o != null)
|
||||
o.release();
|
||||
v.removeElementAt(0);
|
||||
}
|
||||
rot.remove(t_name);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void addObject(JacobObject o) {
|
||||
String t_name = Thread.currentThread().getName();
|
||||
//System.out.println(t_name + " add:"+o+"->"+o.getClass().getName());
|
||||
Vector v = (Vector) rot.get(t_name);
|
||||
if (v == null) {
|
||||
// this thread has not been initialized as a COM thread
|
||||
// so make it part of MTA for backwards compatibility
|
||||
ComThread.InitMTA(false);
|
||||
addThread();
|
||||
v = (Vector) rot.get(t_name);
|
||||
}
|
||||
if (v != null) {
|
||||
v.addElement(o);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("jacob");
|
||||
}
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2004 Sourceforge JACOB Project.
|
||||
* All rights reserved. Originator: Dan Adler (http://danadler.com).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Redistributions in any form must be accompanied by information on
|
||||
* how to obtain complete source code for the JACOB software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jacob.com;
|
||||
|
||||
/**
|
||||
* The multi-format data type used for all call backs and most
|
||||
* communications between Java and COM
|
||||
*/
|
||||
public class Variant extends JacobObject implements java.io.Serializable
|
||||
{
|
||||
int m_pVariant = 0;
|
||||
|
||||
public static final short VariantEmpty = 0;
|
||||
public static final short VariantNull = 1;
|
||||
public static final short VariantShort = 2;
|
||||
public static final short VariantInt = 3;
|
||||
public static final short VariantFloat = 4;
|
||||
public static final short VariantDouble = 5;
|
||||
public static final short VariantCurrency = 6;
|
||||
public static final short VariantDate = 7;
|
||||
public static final short VariantString = 8;
|
||||
public static final short VariantDispatch = 9;
|
||||
public static final short VariantError = 10;
|
||||
public static final short VariantBoolean = 11;
|
||||
public static final short VariantVariant = 12;
|
||||
public static final short VariantObject = 13;
|
||||
public static final short VariantByte = 17;
|
||||
public static final short VariantTypeMask = 4095;
|
||||
public static final short VariantArray = 8192;
|
||||
public static final short VariantByref = 16384;
|
||||
|
||||
public native int toInt();
|
||||
public native double toDate();
|
||||
public native boolean toBoolean();
|
||||
public native EnumVariant toEnumVariant();
|
||||
|
||||
public native void getNull();
|
||||
public native void putNull();
|
||||
|
||||
public native Variant cloneIndirect();
|
||||
public native double toDouble();
|
||||
public native long toCurrency();
|
||||
|
||||
// superceded by SafeArray
|
||||
public void putVariantArray(Variant[] in)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
// superceded by SafeArray
|
||||
public Variant[] getVariantArray()
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
// superceded by SafeArray
|
||||
public void putByteArray(Object in)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public native void putShortRef(short in);
|
||||
public native void putIntRef(int in);
|
||||
public native void putDoubleRef(double in);
|
||||
public native void putDateRef(double in);
|
||||
public native void putStringRef(String in);
|
||||
public native short getShortRef();
|
||||
public native int getIntRef();
|
||||
public native void putShort(short in);
|
||||
public native short getShort();
|
||||
public native double getDoubleRef();
|
||||
public native double getDateRef();
|
||||
public native String getStringRef();
|
||||
|
||||
// superceded by SafeArray
|
||||
public Object toCharArray()
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public native void VariantClear();
|
||||
public native Dispatch toDispatch();
|
||||
public native Object clone();
|
||||
public native String toString();
|
||||
public native int getInt();
|
||||
public native double getDate();
|
||||
public native void putInt(int in);
|
||||
public native void putDate(double in);
|
||||
public native byte toByte();
|
||||
|
||||
public Object getDispatch() { return toDispatch(); }
|
||||
public void putDispatch(Object in) { putObject(in); }
|
||||
|
||||
public native boolean getBoolean();
|
||||
public native byte getByte();
|
||||
public native void putBoolean(boolean in);
|
||||
public native void putByte(byte in);
|
||||
public native int toError();
|
||||
|
||||
public Object toObject()
|
||||
{
|
||||
return toDispatch();
|
||||
}
|
||||
|
||||
public native void getEmpty();
|
||||
public native void putEmpty();
|
||||
public native int getError();
|
||||
public native void putError(int in);
|
||||
public native double getDouble();
|
||||
public Object getObject()
|
||||
{
|
||||
return toDispatch();
|
||||
}
|
||||
|
||||
public native void putCurrency(long in);
|
||||
|
||||
public native void putObject(Object in);
|
||||
|
||||
public native void putDouble(double in);
|
||||
public native long getCurrency();
|
||||
public native void putFloatRef(float in);
|
||||
public native void putCurrencyRef(long in);
|
||||
public native void putErrorRef(int in);
|
||||
public native void putBooleanRef(boolean in);
|
||||
|
||||
public void putObjectRef(Object in)
|
||||
{
|
||||
putObject(in);
|
||||
}
|
||||
|
||||
public native void putByteRef(byte in);
|
||||
public native String getString();
|
||||
public native void putString(String in);
|
||||
public native float getFloatRef();
|
||||
public native long getCurrencyRef();
|
||||
public native int getErrorRef();
|
||||
public native boolean getBooleanRef();
|
||||
public native Object getObjectRef();
|
||||
public native byte getByteRef();
|
||||
public native float toFloat();
|
||||
|
||||
/**
|
||||
* By default toSafeArray makes a deep copy due to the fact
|
||||
* that this Variant owns the embedded SafeArray and will
|
||||
* destroy it when it gc's
|
||||
*/
|
||||
public SafeArray toSafeArray()
|
||||
{
|
||||
return toSafeArray(true);
|
||||
}
|
||||
|
||||
public native SafeArray toSafeArray(boolean deepCopy);
|
||||
public native void putSafeArrayRef(SafeArray in);
|
||||
public native void putSafeArray(SafeArray in);
|
||||
|
||||
public native void noParam();
|
||||
|
||||
// superceded by SafeArray
|
||||
public void putCharArray(Object in)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public native float getFloat();
|
||||
public native void putFloat(float in);
|
||||
|
||||
public void putDispatchRef(Object in) { putDispatch(in); }
|
||||
public Object getDispatchRef() { return getDispatch(); }
|
||||
|
||||
// superceded by SafeArray
|
||||
public void putVariantArrayRef(Variant[] in)
|
||||
{
|
||||
throw new ClassCastException("Not implemented");
|
||||
}
|
||||
|
||||
// superceded by SafeArray
|
||||
public Variant[] getVariantArrayRef()
|
||||
{
|
||||
throw new ClassCastException("Not implemented");
|
||||
}
|
||||
|
||||
public native void changeType(short in);
|
||||
|
||||
public void changeType(int in)
|
||||
{
|
||||
changeType((short)in);
|
||||
}
|
||||
|
||||
public Object toScriptObject() { return toDispatch(); }
|
||||
|
||||
public Variant()
|
||||
{
|
||||
init();
|
||||
putEmpty();
|
||||
}
|
||||
|
||||
public Variant(int in)
|
||||
{
|
||||
init();
|
||||
putInt(in);
|
||||
}
|
||||
|
||||
public Variant(double in)
|
||||
{
|
||||
init();
|
||||
putDouble(in);
|
||||
}
|
||||
|
||||
public Variant(boolean in)
|
||||
{
|
||||
init();
|
||||
putBoolean(in);
|
||||
}
|
||||
|
||||
public Variant(String in)
|
||||
{
|
||||
init();
|
||||
putString(in);
|
||||
}
|
||||
|
||||
public Variant(SafeArray in,boolean fByRef)
|
||||
{
|
||||
init();
|
||||
if (fByRef) {
|
||||
putSafeArrayRef(in);
|
||||
} else {
|
||||
putSafeArray(in);
|
||||
}
|
||||
}
|
||||
|
||||
public Variant(Object in)
|
||||
{
|
||||
this(in, false);
|
||||
}
|
||||
|
||||
public Variant(Object o,boolean fByRef)
|
||||
{
|
||||
init();
|
||||
if (o == null) {
|
||||
putEmpty();
|
||||
} else if (o instanceof Integer) {
|
||||
if (fByRef) putIntRef(((Integer)o).intValue());
|
||||
else putInt(((Integer)o).intValue());
|
||||
} else if (o instanceof String) {
|
||||
if (fByRef) putStringRef((String)o);
|
||||
else putString((String)o);
|
||||
} else if (o instanceof Boolean) {
|
||||
if (fByRef) putBooleanRef(((Boolean)o).booleanValue());
|
||||
else putBoolean(((Boolean)o).booleanValue());
|
||||
} else if (o instanceof Double) {
|
||||
if (fByRef) putDoubleRef(((Double)o).doubleValue());
|
||||
else putDouble(((Double)o).doubleValue());
|
||||
} else if (o instanceof Float) {
|
||||
if (fByRef) putFloatRef(((Float)o).floatValue());
|
||||
else putFloat(((Float)o).floatValue());
|
||||
} else if (o instanceof SafeArray) {
|
||||
if (fByRef) putSafeArrayRef((SafeArray)o);
|
||||
else putSafeArray((SafeArray)o);
|
||||
} else {
|
||||
if (fByRef) putObjectRef(o); else putObject(o);
|
||||
}
|
||||
}
|
||||
|
||||
//weird constructors
|
||||
public Variant(int in,int in1)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public Variant(int in,boolean in1)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public Variant(int in,double in1)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public Variant(int in,Object in1)
|
||||
{
|
||||
throw new ComFailException("Not implemented");
|
||||
}
|
||||
|
||||
public native short getvt();
|
||||
public native short toShort();
|
||||
|
||||
// call this to explicitly release the com object before gc
|
||||
public native void release();
|
||||
|
||||
protected native void init();
|
||||
|
||||
protected void finalize()
|
||||
{
|
||||
//System.out.println("Variant finalize start:"+m_pVariant);
|
||||
if (m_pVariant != 0) release();
|
||||
//System.out.println("Variant finalize end");
|
||||
}
|
||||
|
||||
|
||||
// superceded by SafeArray
|
||||
public Variant[] toVariantArray()
|
||||
{
|
||||
throw new ClassCastException("Not implemented");
|
||||
}
|
||||
|
||||
// superceded by SafeArray
|
||||
public Object toByteArray()
|
||||
{
|
||||
throw new ClassCastException("Not implemented");
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("jacob");
|
||||
}
|
||||
|
||||
// serialization support
|
||||
private void writeObject(java.io.ObjectOutputStream oos)
|
||||
{
|
||||
try {
|
||||
Save(oos);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream ois)
|
||||
{
|
||||
try {
|
||||
Load(ois);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// is the variant null or empty or error or null disp
|
||||
public native boolean isNull();
|
||||
|
||||
public native void Save(java.io.OutputStream os)
|
||||
throws java.io.IOException;
|
||||
|
||||
public native void Load(java.io.InputStream is)
|
||||
throws java.io.IOException;
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ xmlns="http://www.w3.org/TR/REC-html40">
|
||||
<meta name=ProgId content=Word.Document>
|
||||
<meta name=Generator content="Microsoft Word 11">
|
||||
<meta name=Originator content="Microsoft Word 11">
|
||||
<link rel=File-List href="EventsAndCallBacks_files/filelist.xml">
|
||||
<link rel=File-List href="EventCallbacks_files/filelist.xml">
|
||||
<title>Jacob can register Java classes for MS application events or callbacks</title>
|
||||
<!--[if gte mso 9]><xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
@@ -75,6 +75,38 @@ div.Section1
|
||||
mso-level-number-position:left;
|
||||
margin-left:42.0pt;
|
||||
text-indent:-24.0pt;}
|
||||
@list l0:level2
|
||||
{mso-level-tab-stop:1.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level3
|
||||
{mso-level-tab-stop:1.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level4
|
||||
{mso-level-tab-stop:2.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level5
|
||||
{mso-level-tab-stop:2.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level6
|
||||
{mso-level-tab-stop:3.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level7
|
||||
{mso-level-tab-stop:3.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level8
|
||||
{mso-level-tab-stop:4.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l0:level9
|
||||
{mso-level-tab-stop:4.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1
|
||||
{mso-list-id:1316765558;
|
||||
mso-list-type:hybrid;
|
||||
@@ -85,6 +117,38 @@ div.Section1
|
||||
mso-level-number-position:left;
|
||||
margin-left:42.0pt;
|
||||
text-indent:-24.0pt;}
|
||||
@list l1:level2
|
||||
{mso-level-tab-stop:1.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level3
|
||||
{mso-level-tab-stop:1.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level4
|
||||
{mso-level-tab-stop:2.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level5
|
||||
{mso-level-tab-stop:2.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level6
|
||||
{mso-level-tab-stop:3.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level7
|
||||
{mso-level-tab-stop:3.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level8
|
||||
{mso-level-tab-stop:4.0in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
@list l1:level9
|
||||
{mso-level-tab-stop:4.5in;
|
||||
mso-level-number-position:left;
|
||||
text-indent:-.25in;}
|
||||
ol
|
||||
{margin-bottom:0in;}
|
||||
ul
|
||||
@@ -124,48 +188,48 @@ is:</p>
|
||||
<p class=MsoPlainText><o:p> </o:p></p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>1)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>Application thread creates an instance of the
|
||||
event handler and registers it with Jacob</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>2)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The application continues on doing other work.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>3)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>Some time later, the MS application takes some
|
||||
action and initiates the event callback.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>4)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The Java VM receives the event and spins up a
|
||||
new thread to handle it.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>5)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
|
||||
in the <span class=SpellE>dll</span> is called by the VM.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>6)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
|
||||
creates Variant objects to handle the parameters of the passed in event.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>7)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
|
||||
@@ -173,7 +237,7 @@ uses reflection to map the event name to a method name with the exact same
|
||||
name.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l1 level1 lfo1;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l1 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>8)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The Jacob <span class=SpellE>EventProxy</span>
|
||||
@@ -214,60 +278,66 @@ class loader of the event handler class.</p>
|
||||
<p class=MsoPlainText><o:p> </o:p></p>
|
||||
|
||||
<p class=MsoPlainText>The Jacob <span class=SpellE>EventProxy</span> class has
|
||||
been modified (off of the 1.8 tree) so that it takes a two step approach to towards
|
||||
fixing these problems.</p>
|
||||
been modified (off of the 1.8 tree) so that it takes a two step approach to
|
||||
towards fixing these problems.</p>
|
||||
|
||||
<p class=MsoPlainText><span style='mso-tab-count:1'> </span><span
|
||||
style='mso-tab-count:1'> </span></p>
|
||||
<p class=MsoPlainText><span style='mso-tab-count:2'> </span></p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l0 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>1)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>The <span class=SpellE>EventProxy</span>
|
||||
constructor now accepts an extra object, an instance of the Variant class.<span
|
||||
style='mso-spacerun:yes'> </span>This gives the <span class=SpellE>EventProxy</span>
|
||||
a way to get to the Variant class and thus to its <span class=SpellE>classloader</span>.
|
||||
All of the callers of the constructor have been modified to pass a Variant
|
||||
object to the <span class=SpellE>EventProxy</span> without programmer
|
||||
intervention.</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>2)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]><span class=SpellE>EventProxy</span> first
|
||||
attempts to locate the Variant class using <span class=SpellE>FindClass</span>()</p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l0 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>2)<span
|
||||
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>3)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>Failing that, it looks to see if the event
|
||||
callback object implements <span class=SpellE><span class=GramE>getVariantClass</span></span><span
|
||||
class=GramE>(</span>) that returns the <span class=SpellE>Variant.class</span>
|
||||
object.<span style='mso-spacerun:yes'> </span>If so, it uses that class to
|
||||
create variants for the callback parameters.</p>
|
||||
</span></span></span><![endif]>Failing that, it looks to see if a variant
|
||||
object had been passed in. If so, it calls <span class=GramE>class(</span>) and
|
||||
goes from there.<span style='mso-spacerun:yes'> </span></p>
|
||||
|
||||
<p class=MsoPlainText style='margin-left:42.0pt;text-indent:-24.0pt;mso-list:
|
||||
l0 level1 lfo2;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>3)<span
|
||||
l0 level1 lfo4;tab-stops:list 42.0pt'><![if !supportLists]><span
|
||||
style='mso-fareast-font-family:"Courier New"'><span style='mso-list:Ignore'>4)<span
|
||||
style='font:7.0pt "Times New Roman"'>
|
||||
</span></span></span><![endif]>If all that fails, it logs a message and then
|
||||
fails in the spectacular fashion of the previous versions.</p>
|
||||
|
||||
<p class=MsoPlainText><o:p> </o:p></p>
|
||||
|
||||
<p class=MsoPlainText>This means developers can receive call back events in JWS
|
||||
other Java launching programs by implementing <span class=SpellE><span
|
||||
class=GramE>getVariantClass</span></span><span class=GramE>(</span>) on all of
|
||||
their classes that receive Microsoft Events.<span style='mso-spacerun:yes'>
|
||||
</span>The <span class=SpellE><span class=GramE>getVariantClass</span></span><span
|
||||
class=GramE>(</span>) method has the added benefit of providing a spot for the
|
||||
thread <span class=SpellE>classloader</span> to be set:</p>
|
||||
<p class=MsoPlainText>Developers can receive call back events in JWS other Java
|
||||
launching programs without implementing any additional code.<span
|
||||
style='mso-spacerun:yes'> </span>They should be aware that their callback
|
||||
methods may need to set the class <span class=GramE>loader.:</span></p>
|
||||
|
||||
<p class=MsoPlainText><span style='mso-tab-count:1'> </span>Public Class <span
|
||||
class=SpellE><span class=GramE>getVariantClass</span></span><span class=GramE>(</span>){</p>
|
||||
<p class=MsoPlainText><span style='mso-tab-count:1'> </span>Public xxx <span
|
||||
class=SpellE><span class=GramE>someHandler</span></span><span class=GramE>(</span>Variant[]
|
||||
<span class=SpellE>foo</span>){</p>
|
||||
|
||||
<p class=MsoPlainText><span style='mso-tab-count:1'> </span><span
|
||||
style='mso-tab-count:1'> </span><span class=SpellE><span class=GramE>Thread.currentThread</span></span><span
|
||||
<p class=MsoPlainText><span style='mso-tab-count:2'> </span><span
|
||||
class=SpellE><span class=GramE>Thread.currentThread</span></span><span
|
||||
class=GramE>(</span>).<span class=SpellE>setContextClassLoader</span>(</p>
|
||||
|
||||
<p class=MsoPlainText><span style='mso-tab-count:3'> </span><span
|
||||
class=SpellE><span class=GramE>this.getClass</span></span><span class=GramE>(</span>).<span
|
||||
class=SpellE>getClassLoader</span>());</p>
|
||||
|
||||
<p class=MsoPlainText><span style='mso-tab-count:1'> </span><span
|
||||
style='mso-tab-count:1'> </span><span class=GramE>return</span> <span
|
||||
class=SpellE>Variant.class</span></p>
|
||||
<p class=MsoPlainText><span style='mso-tab-count:2'> </span>// do
|
||||
something</p>
|
||||
|
||||
<p class=MsoPlainText><span style='mso-tab-count:1'> </span>}</p>
|
||||
|
||||
@@ -276,6 +346,8 @@ class=SpellE>Variant.class</span></p>
|
||||
<p class=MsoPlainText>There may still be a dual event queue issue in JWS
|
||||
applications that needs to be looked at.</p>
|
||||
|
||||
<p class=MsoPlainText><o:p> </o:p></p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
69
docs/HowToBuild.txt
Normal file
69
docs/HowToBuild.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
(2/2005)
|
||||
To build and run:
|
||||
|
||||
Unpack the source archive or check the files out of CVS into d:\jacob
|
||||
|
||||
Install the following tools
|
||||
Microsfot Visual Studio, a stripped down version is available from the MS web site.
|
||||
Eclipse from www.eclipse.org.
|
||||
Java jdk 1.4 (this was built using 1.4.2.06)
|
||||
|
||||
The following configuration was used by most of the development team:
|
||||
JDK = d:\j2sdk1.4.2_06
|
||||
DEST_DIR = d:\jacob
|
||||
MSDEVDIR = d:\apps\\"Microsoft Visual Studio"\VC98
|
||||
|
||||
This project has been converted completely over to ANT. You can
|
||||
run ANT from inside of eclipse or from the command line.
|
||||
The ant process is driven off of a configuration file
|
||||
compilation_tools.properties. Instructions on the information required
|
||||
in that file are contained in build.xml in the root directory.
|
||||
|
||||
Ant, via build.xml will do the following with teh default target.
|
||||
Build the Java code
|
||||
Build the jni code
|
||||
create the dll
|
||||
create jar file
|
||||
|
||||
The package target creates the
|
||||
javadoc and
|
||||
zip files
|
||||
|
||||
ECLIPSE
|
||||
|
||||
Eclipse users will have to do some minor tweaks to their project if they
|
||||
want to use the integrated build process. This is because the unit
|
||||
tests are com.jacob.com files located in the unittest directory while
|
||||
the jacob files themselves are in com.jacob.com off the root directory.
|
||||
(Eventually the the jacob files will be moved to src)
|
||||
Eclipse automatically adds the whole project as a source directory
|
||||
Remove the root of the project from the build path
|
||||
Add folders samples, src and unittest to the build path
|
||||
Exclude *.txt from each of the newly added folders.
|
||||
|
||||
A couple of the samples require a J2EE library in order to compile. This
|
||||
means you'll have to add a J2EE jar file to your classpath. This
|
||||
isn't a problem when using ANT because the Servlet examples are excluded
|
||||
from the build.
|
||||
|
||||
|
||||
|
||||
--- old instructions for makefiles that no longer exist --
|
||||
|
||||
To build:
|
||||
Run VCVARS32 to set up your MS Visual C++ environment
|
||||
cd d:\jacob
|
||||
nmake
|
||||
|
||||
(from dan)I developed this with the C++ compiler and ATL version
|
||||
that ship with VC++ 6.0, so I'm not sure if different versions will
|
||||
work.
|
||||
|
||||
This is currently designed to compile against JDK 1.4.2. The future
|
||||
of the Microsoft SDK is in doubt so support may be discontinued
|
||||
in the future.
|
||||
|
||||
|
||||
The java code is in com\jacob\*.
|
||||
The C++ code is in .\jni.
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
<H1>COM Object Lifetime in JACOB</H1>
|
||||
<p>
|
||||
<H2>introduction</H2>
|
||||
<p>
|
||||
JACOB Version 1.7 implements a new
|
||||
<a href="JacobThreading.html">Threading Model</a> that is more
|
||||
compatible with COM apartments. There is also an incompatibility
|
||||
between the Java object lifetime model and that of COM objects.
|
||||
COM Objects live and die by their reference count, whereas Java
|
||||
objects are collected by the Garbage Collector (GC) based on algortihms
|
||||
that are hidden from the user.
|
||||
<H2>COM Object Lifetime in JACOB Prior to Version 1.7</H2>
|
||||
<p>
|
||||
In version 1.6 and earlier, JACOB objects which wrapped COM objects
|
||||
had <code>finalize()</code> methods that would call a native
|
||||
<code>release</code> method which would call a COM <code>Release</code>.
|
||||
<p>
|
||||
This has many problems. For one thing, the GC may take a long time to
|
||||
kick in and resource consumption may grow. However, the more problematic
|
||||
issue is that finalizers are called from a separate thread, and, as was
|
||||
discussed in the <a href="JacobThreading.html">Threading Model</a>
|
||||
document, this can result in COM errors if the object is running in an
|
||||
STA. Even if the object is running in an MTA, the finalizer may decide
|
||||
to run after we have terminated the thread that holds the component, in
|
||||
which case we would get fatal errors and crashes.
|
||||
<H2>COM Object Lifetime in JACOB in Version 1.7</H2>
|
||||
<p>
|
||||
In Version 1.7, all JACOB objects which wrap COM objects extend
|
||||
<code>com.jacob.com.JacobObject</code>. This object has some special
|
||||
code to register itself with a <code>com.jacob.com.ROT</code> object
|
||||
which represents a Running Object Table (ROT). This table maps a
|
||||
Thread to the set of JacobObjects created in that thread. Therefore,
|
||||
when you call <code>ComThread.Release()</code>, the ROT checks whether
|
||||
that thread has created any objects, and these objects are released
|
||||
by calling their native <code>release</code> method (which is public).
|
||||
<p>
|
||||
This lifetime management method ties the lifecycle to the thread's
|
||||
lifecycle rather than the GC. The JacobObject's still have finalizers,
|
||||
but they will typically not perform the native <code>release</code>
|
||||
since that has already been called. The native <code>release</code>
|
||||
methods were written such that you can call them multiple times without
|
||||
worrying - since they zero out the native pointer when called the first
|
||||
time.
|
||||
<p>
|
||||
If you choose to call <code>release</code> methods on your objects
|
||||
yourself, that is allowed. In that case, when the thread is released
|
||||
the release calls will be no-ops.
|
||||
<p>
|
||||
It becomes important for you to call <code>ComThread.Release()</code>
|
||||
on any thread before you allow it to exit, otherwise you may get
|
||||
some random crashes later on in your code.
|
||||
<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.
|
||||
@@ -1,410 +1,410 @@
|
||||
<H1>COM Apartments in JACOB</H1>
|
||||
<p>
|
||||
<H2>introduction</H2>
|
||||
<p>
|
||||
The COM model for Threading differs from the Java model.
|
||||
In COM, each component can declare whether or not it support
|
||||
multi-threading.
|
||||
|
||||
You can find some basic information about COM threading at:
|
||||
<p>
|
||||
<a href="http://www.execpc.com/~gopalan/com/com_threading.html">
|
||||
http://www.execpc.com/~gopalan/com/com_threading.html</a>
|
||||
<p>
|
||||
<a href="www.microsoft.com/msj/0297/apartment/apartment.htm">
|
||||
www.microsoft.com/msj/0297/apartment/apartment.htm</a>
|
||||
<p>
|
||||
<a href="http://www.cswl.com/whiteppr/white/multithreading.html">
|
||||
http://www.cswl.com/whiteppr/white/multithreading.html
|
||||
</a>
|
||||
<p>
|
||||
The term <b>Single Threaded Apartment (STA)</b> refers to a thread
|
||||
where all COM objects created in that thread are
|
||||
single-threaded. This can manifest itself in two ways:
|
||||
<br>
|
||||
Either all calls into that component are made from the same thread
|
||||
that created the component
|
||||
<br>
|
||||
OR any call that is made from another thread gets serialized by COM.
|
||||
This serialization of calls is done by using a Windows message loop and
|
||||
posting messages to a hidden window (I'm not kidding). The way COM
|
||||
achieves this is by requiring any other thread to make calls through
|
||||
a local Proxy object rather than the original object (more on this
|
||||
when we discuss the JACOB DispatchProxy class).
|
||||
<p>
|
||||
What does this mean for a Java application? If you are using a component
|
||||
that declares itself as <b>ThreadingModel "Apartment"</b> (you can
|
||||
find this out by looking in the registry under its CLSID), and you plan
|
||||
to create, use and destroy this component in one thread - then you are
|
||||
following the rules of an STA and you can declare the thread as an
|
||||
STA thread.
|
||||
<p>
|
||||
On the other hand, if you need to make method calls from another thread
|
||||
(e.g. in a servlet) then you have a few choices. Either you
|
||||
create the component in its own STA, by extending
|
||||
<code>com.jacob.com.STA</code>, and use the
|
||||
<code>com.jacob.com.DispatchProxy</code> class to pass the Dispatch
|
||||
pointer between threads, or you can declare your thread as an MTA
|
||||
thread. In that case, COM will make
|
||||
the cross-thread calls into the STA that is running your component.
|
||||
If you create an Apartment threaded component in the MTA,
|
||||
COM will automatically create an STA for you and put your
|
||||
component in there, and then marshall all the calls.
|
||||
<p>
|
||||
This brings us to the notion of a <b>Main STA</b>. COM requires that
|
||||
if there is any Apartment threaded component in your application, then
|
||||
the first STA created is tagged as the <b>Main STA</b>. COM uses the
|
||||
Main STA to create all the Apartment threaded components that are
|
||||
created from an MTA thread. The problem is that if you have already
|
||||
created an STA, then COM will pick that as the Main STA, and if you
|
||||
ever exit that thread - the whole application will exit.
|
||||
|
||||
<H2>COM Threads in JACOB Prior to Version 1.7</H2>
|
||||
<p>
|
||||
Up until version 1.7 of JACOB, there was only one model available
|
||||
in JACOB:
|
||||
<ul>
|
||||
<li>
|
||||
Before version 1.6: All threads were automatically initialized as STAs.
|
||||
</li>
|
||||
<li>
|
||||
In version 1.6: All threads were automatically initialized as MTAs.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
The reason for the change in default was that tagging a Java thread
|
||||
as an STA can cause problems. Any Java Swing application, as well as
|
||||
servlets and applets need to be able to make calls from multiple
|
||||
threads. If you try to make COM method calls across STA threads - it
|
||||
will fail!
|
||||
<p>
|
||||
In most cases, the default chosen by JACOB 1.6 (MTA) works fine, however
|
||||
there are some notable exceptions that have caused people grief. One
|
||||
such exception is in the case of MAPI. It turns out that if you try to
|
||||
create a MAPI object from an MTA thread - it simply fails and exits.
|
||||
This has caused some people to recompile JACOB 1.6 back with the STA
|
||||
default.
|
||||
<p>
|
||||
There is another problem with MTA threads: when you are using Apartment
|
||||
threaded components, we already noted that COM will create the
|
||||
components in the Main STA. If one doesn't exist, COM will create it.
|
||||
However, this means that <b>all</b> Apartment threaded components will
|
||||
be created in the <b>same STA</b>. This creates a bottleneck, and a
|
||||
dependency between unrelated components. Also, if that STA exits, then
|
||||
all components are destroyed and the application will likely crash.
|
||||
|
||||
<H2>COM Threads in JACOB Version 1.7</H2>
|
||||
<p>
|
||||
In Version 1.7 we have added finer grained control to allow the
|
||||
Java programmer to control how COM creates its components.
|
||||
Unfortunately, this means that you need to have a pretty good
|
||||
understanding of the dark and mystical subject of COM Apartments.
|
||||
There are a few different cases you need to consider:
|
||||
<H3>Default</H3>
|
||||
<p>
|
||||
If you simply run code that was created in Version 1.6 and ignore
|
||||
the COM threading issue, then you will get the same behavior as in 1.6:
|
||||
Each java thread will be an MTA thread, and all Apartment threaded
|
||||
components will be created by COM in its own Main STA. This typically
|
||||
works for most applications (exceptions noted above).
|
||||
<H3>Create Your Own Apartment</H3>
|
||||
<p>
|
||||
To declare an MTA thread use the following template:
|
||||
<br>
|
||||
<pre>
|
||||
<code>
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
If you want JACOB to create its own Main STA (rather than having COM
|
||||
choose an STA for you), then you should use:
|
||||
<br>
|
||||
<code>
|
||||
<pre>
|
||||
Thread 1:
|
||||
ComThread.InitMTA(true); // a true tells JACOB to create a Main STA
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
Thread 2:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
...
|
||||
ComThread.quitMainSTA();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
In this case, you can also create the Main STA explicitly:
|
||||
<br>
|
||||
<code>
|
||||
<pre>
|
||||
ComThread.startMainSTA();
|
||||
...
|
||||
...
|
||||
Thread 1:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
Thread 2:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
...
|
||||
ComThread.quitMainSTA();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
In the latter case, all Apartment threaded components will be created in
|
||||
JACOB's main STA. This still has all the problems of components
|
||||
sharing the same Main STA and creating a bottleneck. To avoid that,
|
||||
you can also create STA threads yourself:
|
||||
<br>
|
||||
<code>
|
||||
<pre>
|
||||
ComThread.startMainSTA();
|
||||
...
|
||||
...
|
||||
Thread 1:
|
||||
ComThread.InitSTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
Thread 2:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
...
|
||||
ComThread.quitMainSTA();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
In this example, thread 1 is an STA and thread 2 is an MTA. You could
|
||||
omit the call to ComThread.startMainSTA(), but if you do, then COM will
|
||||
make the first STA your main one, and then if you exit that thread,
|
||||
the application will crash.
|
||||
<p>
|
||||
Actually, Thread 1 is <i>almost</i> an STA. It's lacking a windows
|
||||
message loop. So, this type of STA is fine as long as you are creating
|
||||
a component and using it in the same thread, and not makind event
|
||||
callbacks.
|
||||
<H3>JACOB's STA Class</H3>
|
||||
<p>
|
||||
If you want to create an true STA where you can create a component and
|
||||
then let other threads call methods on it, then you need a windows
|
||||
message loop. JACOB provides a class called:
|
||||
<code>com.jacob.com.STA</code> which does exactly this.
|
||||
<code>
|
||||
<pre>
|
||||
public class com.jacob.com.STA extends java.lang.Thread
|
||||
{
|
||||
public com.jacob.com.STA();
|
||||
public boolean OnInit(); // you override this
|
||||
public void OnQuit(); // you override this
|
||||
public void quit(); // you can call this from ANY thread
|
||||
}
|
||||
</pre>
|
||||
</code>
|
||||
<p>
|
||||
The STA class extends
|
||||
<code>java.lang.Thread</code> and it provides you with two methods
|
||||
that you can override: <code>OnInit</code> and <code>OnQuit</code>.
|
||||
These methods are called from the thread's <code>run</code> method
|
||||
so they will execute in the new thread. These methods allow you to
|
||||
create COM components (Dispatch objects) and release them.
|
||||
To create an STA, you subclass it and override the OnInit.
|
||||
<p>
|
||||
The <code>quit</code> method is the <b>only</b> other method that
|
||||
can be called from any thread. This method uses the Win32 function
|
||||
<code>PostThreadMessage</code> to force the STA's windows message loop
|
||||
to exit, thereby terminating the thread.
|
||||
<p>
|
||||
You will then need to make calls into the component that is running
|
||||
in the STA thread. If you simply try to make calls from another thread
|
||||
on a Dispatch object created in the STA thread, you will get a COM
|
||||
Exception. For more details see:
|
||||
<a href="http://www.develop.com/effectivecom">
|
||||
Don Box 'Effective COM' Rule 29</a>: Don't Access raw
|
||||
interface pointers across apartment boundaries.
|
||||
<H3>The DispatchProxy Class</H3>
|
||||
Since you cannot call methods directly on a Dispatch object created
|
||||
in another STA JACOB provides a method for the class that created
|
||||
the Dispatch object to marshal it to your thread. This is done via
|
||||
the <code>com.jacob.com.DispatchProxy</code> class.
|
||||
<code>
|
||||
<pre>
|
||||
public class DispatchProxy extends JacobObject {
|
||||
public DispatchProxy(Dispatch);
|
||||
public Dispatch toDispatch();
|
||||
|
||||
public native void release();
|
||||
public void finalize();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
This class works as follows: the thread that created the Dispatch
|
||||
object constructs an instance of DispatchProxy(Dispatch) with the
|
||||
Dispatch as a parameter. This instance can then be accessed from
|
||||
another thread, which will invoke its <code>toDispatch</code> method
|
||||
proxy as if it were local to your thread. COM will do the inter-thread
|
||||
marshalling transparently.
|
||||
<p>
|
||||
The following example is part of samples/test/ScriptTest2.java in the
|
||||
JACOB distribution. It shows how you can create the ScriptControl
|
||||
in one STA thread and make method calls on it from another:
|
||||
<code>
|
||||
<pre>
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class ScriptTest2 extends STA
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static Dispatch sControl = null;
|
||||
public static DispatchProxy sCon = null;
|
||||
|
||||
public boolean OnInit()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("OnInit");
|
||||
System.out.println(Thread.currentThread());
|
||||
String lang = "VBScript";
|
||||
|
||||
sC = new ActiveXComponent("ScriptControl");
|
||||
sControl = (Dispatch)sC.getObject();
|
||||
|
||||
// sCon can be called from another thread
|
||||
sCon = new DispatchProxy(sControl);
|
||||
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuit()
|
||||
{
|
||||
System.out.println("OnQuit");
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
try {
|
||||
ComThread.InitSTA();
|
||||
ScriptTest2 script = new ScriptTest2();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// get a thread-local Dispatch from sCon
|
||||
Dispatch sc = sCon.toDispatch();
|
||||
|
||||
// call a method on the thread-local Dispatch obtained
|
||||
// from the DispatchProxy. If you try to make the same
|
||||
// method call on the sControl object - you will get a
|
||||
// ComException.
|
||||
Variant result = Dispatch.call(sc, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
script.quit();
|
||||
System.out.println("called quit");
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</code>
|
||||
<p>
|
||||
You can try to modify the <code>Dispatch.call</code> invocation in
|
||||
the main thread to use <code>sControl</code> directly, and you will see
|
||||
that it fails. Notice that once we construct the ScriptTest2 object
|
||||
in the main thread, we sleep for a second to allow the other thread
|
||||
time to initialize itself.
|
||||
<p>
|
||||
The STA thread calls <code>sCon = new DispatchProxy(sControl);</code>
|
||||
to save a global reference to the DispatchProxy that represents the
|
||||
<code>sControl</code> object. The main thread then calls:
|
||||
<code>Dispatch sc = sCon.toDispatch();</code> to get a local Dispatch
|
||||
proxy out of the DispatchProxy object.
|
||||
<p>
|
||||
At most <b>one(!)</b>
|
||||
thread can call toDispatch(), and the call can be made only once.
|
||||
This is because a IStream object is used to pass the proxy, and
|
||||
it is only written once and closed when you read it.
|
||||
If you need multiple threads to access a Dispatch pointer, then
|
||||
create that many DispatchProxy objects. For more details please
|
||||
refer to the Don Box reference above.
|
||||
|
||||
|
||||
<H3>Recommended Procedure</H3>
|
||||
<ul>
|
||||
<li>
|
||||
It is recommended that you always allow JACOB to manage the main STA
|
||||
rather than letting COM create one on its own or tag one of yours.
|
||||
</li>
|
||||
<li>
|
||||
Declare an STA thread using ComThread.InitSTA()
|
||||
if all your
|
||||
method calls for that component are going to come from the same thread.
|
||||
</li>
|
||||
<li>
|
||||
If you want an STA thread that allows other threads to call into it,
|
||||
use the <code>com.jacob.com.STA</code> class as outlined above.
|
||||
</li>
|
||||
<li>
|
||||
If you have a COM component that declares its ThreadingModel as
|
||||
"Free" or "Both", then use the MTA.
|
||||
</li>
|
||||
<li>
|
||||
In most cases, if you need to make method calls from multiple threads,
|
||||
you can simply
|
||||
use MTA threads, and allow COM to create the components in
|
||||
the Main STA. You should only create your own STA's and DispatchProxy
|
||||
if you understand COM well enough to know when the MTA solution
|
||||
will fail or have other shortcomings.
|
||||
<p>
|
||||
There are 3 examples in the samples/test directory that demonstrate
|
||||
these cases:
|
||||
<p>
|
||||
ScriptTest.java - creates an STA for the ScriptControl component and
|
||||
runs all its method calls from that STA.
|
||||
<p>
|
||||
ScriptTest2.java - creates a separate STA thread, and makes
|
||||
method calls into the component from another thread using DispatchProxy.
|
||||
<p>
|
||||
ScriptTest3.java - creates a separate MTA thread, and makes method
|
||||
calls into the component from another MTA thread. This is simpler
|
||||
than ScriptTest2 for most applications.
|
||||
<p>
|
||||
<h3>Default Threading Model</h3>
|
||||
If you create a new thread, and don't call
|
||||
<code>ComThread.InitSTA()</code> or <code>ComThread.InitMTA()</code>
|
||||
on it, then the first time your java code creates a JacobObject, it
|
||||
will try to register itself with the ROT, and when it sees that the
|
||||
current thread is not initialized, it will initialize it as MTA.
|
||||
This means that the code to do this is no longer inside the native
|
||||
jni code - it is now in the <code>com.jacob.com.ROT</code> class.
|
||||
For more details on the ROT, see the
|
||||
<a href="JacobComLifetime.html">Object Lifetime</a> document.
|
||||
<H1>COM Apartments in JACOB</H1>
|
||||
<p>
|
||||
<H2>introduction</H2>
|
||||
<p>
|
||||
The COM model for Threading differs from the Java model.
|
||||
In COM, each component can declare whether or not it support
|
||||
multi-threading.
|
||||
|
||||
You can find some basic information about COM threading at:
|
||||
<p>
|
||||
<a href="http://www.execpc.com/~gopalan/com/com_threading.html">
|
||||
http://www.execpc.com/~gopalan/com/com_threading.html</a>
|
||||
<p>
|
||||
<a href="www.microsoft.com/msj/0297/apartment/apartment.htm">
|
||||
www.microsoft.com/msj/0297/apartment/apartment.htm</a>
|
||||
<p>
|
||||
<a href="http://www.cswl.com/whiteppr/white/multithreading.html">
|
||||
http://www.cswl.com/whiteppr/white/multithreading.html
|
||||
</a>
|
||||
<p>
|
||||
The term <b>Single Threaded Apartment (STA)</b> refers to a thread
|
||||
where all COM objects created in that thread are
|
||||
single-threaded. This can manifest itself in two ways:
|
||||
<br>
|
||||
Either all calls into that component are made from the same thread
|
||||
that created the component
|
||||
<br>
|
||||
OR any call that is made from another thread gets serialized by COM.
|
||||
This serialization of calls is done by using a Windows message loop and
|
||||
posting messages to a hidden window (I'm not kidding). The way COM
|
||||
achieves this is by requiring any other thread to make calls through
|
||||
a local Proxy object rather than the original object (more on this
|
||||
when we discuss the JACOB DispatchProxy class).
|
||||
<p>
|
||||
What does this mean for a Java application? If you are using a component
|
||||
that declares itself as <b>ThreadingModel "Apartment"</b> (you can
|
||||
find this out by looking in the registry under its CLSID), and you plan
|
||||
to create, use and destroy this component in one thread - then you are
|
||||
following the rules of an STA and you can declare the thread as an
|
||||
STA thread.
|
||||
<p>
|
||||
On the other hand, if you need to make method calls from another thread
|
||||
(e.g. in a servlet) then you have a few choices. Either you
|
||||
create the component in its own STA, by extending
|
||||
<code>com.jacob.com.STA</code>, and use the
|
||||
<code>com.jacob.com.DispatchProxy</code> class to pass the Dispatch
|
||||
pointer between threads, or you can declare your thread as an MTA
|
||||
thread. In that case, COM will make
|
||||
the cross-thread calls into the STA that is running your component.
|
||||
If you create an Apartment threaded component in the MTA,
|
||||
COM will automatically create an STA for you and put your
|
||||
component in there, and then marshall all the calls.
|
||||
<p>
|
||||
This brings us to the notion of a <b>Main STA</b>. COM requires that
|
||||
if there is any Apartment threaded component in your application, then
|
||||
the first STA created is tagged as the <b>Main STA</b>. COM uses the
|
||||
Main STA to create all the Apartment threaded components that are
|
||||
created from an MTA thread. The problem is that if you have already
|
||||
created an STA, then COM will pick that as the Main STA, and if you
|
||||
ever exit that thread - the whole application will exit.
|
||||
|
||||
<H2>COM Threads in JACOB Prior to Version 1.7</H2>
|
||||
<p>
|
||||
Up until version 1.7 of JACOB, there was only one model available
|
||||
in JACOB:
|
||||
<ul>
|
||||
<li>
|
||||
Before version 1.6: All threads were automatically initialized as STAs.
|
||||
</li>
|
||||
<li>
|
||||
In version 1.6: All threads were automatically initialized as MTAs.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
The reason for the change in default was that tagging a Java thread
|
||||
as an STA can cause problems. Any Java Swing application, as well as
|
||||
servlets and applets need to be able to make calls from multiple
|
||||
threads. If you try to make COM method calls across STA threads - it
|
||||
will fail!
|
||||
<p>
|
||||
In most cases, the default chosen by JACOB 1.6 (MTA) works fine, however
|
||||
there are some notable exceptions that have caused people grief. One
|
||||
such exception is in the case of MAPI. It turns out that if you try to
|
||||
create a MAPI object from an MTA thread - it simply fails and exits.
|
||||
This has caused some people to recompile JACOB 1.6 back with the STA
|
||||
default.
|
||||
<p>
|
||||
There is another problem with MTA threads: when you are using Apartment
|
||||
threaded components, we already noted that COM will create the
|
||||
components in the Main STA. If one doesn't exist, COM will create it.
|
||||
However, this means that <b>all</b> Apartment threaded components will
|
||||
be created in the <b>same STA</b>. This creates a bottleneck, and a
|
||||
dependency between unrelated components. Also, if that STA exits, then
|
||||
all components are destroyed and the application will likely crash.
|
||||
|
||||
<H2>COM Threads in JACOB Version 1.7</H2>
|
||||
<p>
|
||||
In Version 1.7 we have added finer grained control to allow the
|
||||
Java programmer to control how COM creates its components.
|
||||
Unfortunately, this means that you need to have a pretty good
|
||||
understanding of the dark and mystical subject of COM Apartments.
|
||||
There are a few different cases you need to consider:
|
||||
<H3>Default</H3>
|
||||
<p>
|
||||
If you simply run code that was created in Version 1.6 and ignore
|
||||
the COM threading issue, then you will get the same behavior as in 1.6:
|
||||
Each java thread will be an MTA thread, and all Apartment threaded
|
||||
components will be created by COM in its own Main STA. This typically
|
||||
works for most applications (exceptions noted above).
|
||||
<H3>Create Your Own Apartment</H3>
|
||||
<p>
|
||||
To declare an MTA thread use the following template:
|
||||
<br>
|
||||
<pre>
|
||||
<code>
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
If you want JACOB to create its own Main STA (rather than having COM
|
||||
choose an STA for you), then you should use:
|
||||
<br>
|
||||
<code>
|
||||
<pre>
|
||||
Thread 1:
|
||||
ComThread.InitMTA(true); // a true tells JACOB to create a Main STA
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
Thread 2:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
...
|
||||
ComThread.quitMainSTA();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
In this case, you can also create the Main STA explicitly:
|
||||
<br>
|
||||
<code>
|
||||
<pre>
|
||||
ComThread.startMainSTA();
|
||||
...
|
||||
...
|
||||
Thread 1:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
Thread 2:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
...
|
||||
ComThread.quitMainSTA();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
In the latter case, all Apartment threaded components will be created in
|
||||
JACOB's main STA. This still has all the problems of components
|
||||
sharing the same Main STA and creating a bottleneck. To avoid that,
|
||||
you can also create STA threads yourself:
|
||||
<br>
|
||||
<code>
|
||||
<pre>
|
||||
ComThread.startMainSTA();
|
||||
...
|
||||
...
|
||||
Thread 1:
|
||||
ComThread.InitSTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
Thread 2:
|
||||
ComThread.InitMTA();
|
||||
...
|
||||
...
|
||||
ComThread.Release();
|
||||
...
|
||||
...
|
||||
ComThread.quitMainSTA();
|
||||
</pre>
|
||||
</code>
|
||||
<br>
|
||||
In this example, thread 1 is an STA and thread 2 is an MTA. You could
|
||||
omit the call to ComThread.startMainSTA(), but if you do, then COM will
|
||||
make the first STA your main one, and then if you exit that thread,
|
||||
the application will crash.
|
||||
<p>
|
||||
Actually, Thread 1 is <i>almost</i> an STA. It's lacking a windows
|
||||
message loop. So, this type of STA is fine as long as you are creating
|
||||
a component and using it in the same thread, and not makind event
|
||||
callbacks.
|
||||
<H3>JACOB's STA Class</H3>
|
||||
<p>
|
||||
If you want to create an true STA where you can create a component and
|
||||
then let other threads call methods on it, then you need a windows
|
||||
message loop. JACOB provides a class called:
|
||||
<code>com.jacob.com.STA</code> which does exactly this.
|
||||
<code>
|
||||
<pre>
|
||||
public class com.jacob.com.STA extends java.lang.Thread
|
||||
{
|
||||
public com.jacob.com.STA();
|
||||
public boolean OnInit(); // you override this
|
||||
public void OnQuit(); // you override this
|
||||
public void quit(); // you can call this from ANY thread
|
||||
}
|
||||
</pre>
|
||||
</code>
|
||||
<p>
|
||||
The STA class extends
|
||||
<code>java.lang.Thread</code> and it provides you with two methods
|
||||
that you can override: <code>OnInit</code> and <code>OnQuit</code>.
|
||||
These methods are called from the thread's <code>run</code> method
|
||||
so they will execute in the new thread. These methods allow you to
|
||||
create COM components (Dispatch objects) and release them.
|
||||
To create an STA, you subclass it and override the OnInit.
|
||||
<p>
|
||||
The <code>quit</code> method is the <b>only</b> other method that
|
||||
can be called from any thread. This method uses the Win32 function
|
||||
<code>PostThreadMessage</code> to force the STA's windows message loop
|
||||
to exit, thereby terminating the thread.
|
||||
<p>
|
||||
You will then need to make calls into the component that is running
|
||||
in the STA thread. If you simply try to make calls from another thread
|
||||
on a Dispatch object created in the STA thread, you will get a COM
|
||||
Exception. For more details see:
|
||||
<a href="http://www.develop.com/effectivecom">
|
||||
Don Box 'Effective COM' Rule 29</a>: Don't Access raw
|
||||
interface pointers across apartment boundaries.
|
||||
<H3>The DispatchProxy Class</H3>
|
||||
Since you cannot call methods directly on a Dispatch object created
|
||||
in another STA JACOB provides a method for the class that created
|
||||
the Dispatch object to marshal it to your thread. This is done via
|
||||
the <code>com.jacob.com.DispatchProxy</code> class.
|
||||
<code>
|
||||
<pre>
|
||||
public class DispatchProxy extends JacobObject {
|
||||
public DispatchProxy(Dispatch);
|
||||
public Dispatch toDispatch();
|
||||
|
||||
public native void release();
|
||||
public void finalize();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
This class works as follows: the thread that created the Dispatch
|
||||
object constructs an instance of DispatchProxy(Dispatch) with the
|
||||
Dispatch as a parameter. This instance can then be accessed from
|
||||
another thread, which will invoke its <code>toDispatch</code> method
|
||||
proxy as if it were local to your thread. COM will do the inter-thread
|
||||
marshalling transparently.
|
||||
<p>
|
||||
The following example is part of samples/test/ScriptTest2.java in the
|
||||
JACOB distribution. It shows how you can create the ScriptControl
|
||||
in one STA thread and make method calls on it from another:
|
||||
<code>
|
||||
<pre>
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class ScriptTest2 extends STA
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static Dispatch sControl = null;
|
||||
public static DispatchProxy sCon = null;
|
||||
|
||||
public boolean OnInit()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("OnInit");
|
||||
System.out.println(Thread.currentThread());
|
||||
String lang = "VBScript";
|
||||
|
||||
sC = new ActiveXComponent("ScriptControl");
|
||||
sControl = (Dispatch)sC.getObject();
|
||||
|
||||
// sCon can be called from another thread
|
||||
sCon = new DispatchProxy(sControl);
|
||||
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuit()
|
||||
{
|
||||
System.out.println("OnQuit");
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
try {
|
||||
ComThread.InitSTA();
|
||||
ScriptTest2 script = new ScriptTest2();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// get a thread-local Dispatch from sCon
|
||||
Dispatch sc = sCon.toDispatch();
|
||||
|
||||
// call a method on the thread-local Dispatch obtained
|
||||
// from the DispatchProxy. If you try to make the same
|
||||
// method call on the sControl object - you will get a
|
||||
// ComException.
|
||||
Variant result = Dispatch.call(sc, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
script.quit();
|
||||
System.out.println("called quit");
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</code>
|
||||
<p>
|
||||
You can try to modify the <code>Dispatch.call</code> invocation in
|
||||
the main thread to use <code>sControl</code> directly, and you will see
|
||||
that it fails. Notice that once we construct the ScriptTest2 object
|
||||
in the main thread, we sleep for a second to allow the other thread
|
||||
time to initialize itself.
|
||||
<p>
|
||||
The STA thread calls <code>sCon = new DispatchProxy(sControl);</code>
|
||||
to save a global reference to the DispatchProxy that represents the
|
||||
<code>sControl</code> object. The main thread then calls:
|
||||
<code>Dispatch sc = sCon.toDispatch();</code> to get a local Dispatch
|
||||
proxy out of the DispatchProxy object.
|
||||
<p>
|
||||
At most <b>one(!)</b>
|
||||
thread can call toDispatch(), and the call can be made only once.
|
||||
This is because a IStream object is used to pass the proxy, and
|
||||
it is only written once and closed when you read it.
|
||||
If you need multiple threads to access a Dispatch pointer, then
|
||||
create that many DispatchProxy objects. For more details please
|
||||
refer to the Don Box reference above.
|
||||
|
||||
|
||||
<H3>Recommended Procedure</H3>
|
||||
<ul>
|
||||
<li>
|
||||
It is recommended that you always allow JACOB to manage the main STA
|
||||
rather than letting COM create one on its own or tag one of yours.
|
||||
</li>
|
||||
<li>
|
||||
Declare an STA thread using ComThread.InitSTA()
|
||||
if all your
|
||||
method calls for that component are going to come from the same thread.
|
||||
</li>
|
||||
<li>
|
||||
If you want an STA thread that allows other threads to call into it,
|
||||
use the <code>com.jacob.com.STA</code> class as outlined above.
|
||||
</li>
|
||||
<li>
|
||||
If you have a COM component that declares its ThreadingModel as
|
||||
"Free" or "Both", then use the MTA.
|
||||
</li>
|
||||
<li>
|
||||
In most cases, if you need to make method calls from multiple threads,
|
||||
you can simply
|
||||
use MTA threads, and allow COM to create the components in
|
||||
the Main STA. You should only create your own STA's and DispatchProxy
|
||||
if you understand COM well enough to know when the MTA solution
|
||||
will fail or have other shortcomings.
|
||||
<p>
|
||||
There are 3 examples in the samples/test directory that demonstrate
|
||||
these cases:
|
||||
<p>
|
||||
ScriptTest.java - creates an STA for the ScriptControl component and
|
||||
runs all its method calls from that STA.
|
||||
<p>
|
||||
ScriptTest2.java - creates a separate STA thread, and makes
|
||||
method calls into the component from another thread using DispatchProxy.
|
||||
<p>
|
||||
ScriptTest3.java - creates a separate MTA thread, and makes method
|
||||
calls into the component from another MTA thread. This is simpler
|
||||
than ScriptTest2 for most applications.
|
||||
<p>
|
||||
<h3>Default Threading Model</h3>
|
||||
If you create a new thread, and don't call
|
||||
<code>ComThread.InitSTA()</code> or <code>ComThread.InitMTA()</code>
|
||||
on it, then the first time your java code creates a JacobObject, it
|
||||
will try to register itself with the ROT, and when it sees that the
|
||||
current thread is not initialized, it will initialize it as MTA.
|
||||
This means that the code to do this is no longer inside the native
|
||||
jni code - it is now in the <code>com.jacob.com.ROT</code> class.
|
||||
For more details on the ROT, see the
|
||||
<a href="JacobComLifetime.html">Object Lifetime</a> document.
|
||||
344
docs/WhatsNew.html
Normal file
344
docs/WhatsNew.html
Normal file
@@ -0,0 +1,344 @@
|
||||
<h1>What's New in JACOB 1.9</H1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<b>Event Callbacks</b>
|
||||
<ul>
|
||||
|
||||
<li>Variant parameters can now be modified by the receiver to be passed
|
||||
back to the COM caller </li>
|
||||
<li>Callbacks can now be received when running in JWS other launchers where
|
||||
JACOB.jar is not in the system classloader's path.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<b>Dispatch API Clarifications</B>
|
||||
<ul>
|
||||
|
||||
<li>All static method's first parameters have been more strongly typed
|
||||
to the Dispatch class, rather than Object. This may call for code
|
||||
changes in the cases of code that just asigned Dispatch objects
|
||||
to variables of type Object rather than Dispatch or one of its subclasses </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Dispatch subclasses are now supported with pointer modifying constructor</b>
|
||||
<ul>
|
||||
|
||||
<li>Dispatch and ActiveXComponent now includes a constructor to be used by Dispatch subclasses
|
||||
that swaps the pointers around. This eliminates the need for every Dispatch subclass
|
||||
to have a constructor that swapped and nulled out the pointers to the COM layer.
|
||||
All samples have updated to use the new api </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>ActiveXComponent has been upgraded</b><ul>
|
||||
|
||||
<li>ActiveXComponent methods return ActiveXComponets </li>
|
||||
<li>Methods have been added to the ActiveXComponents to retrieve
|
||||
parameters as Dispatch objects or ActiveX components. The
|
||||
Script Tests have been updated to show the same programs in Dispatch
|
||||
format or ActiveXComponentFormat </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Memory Management</b>
|
||||
<ul>
|
||||
|
||||
<li>Beta test option that lets an application use automatic object object
|
||||
removal through the use of weak reference hash maps in the ROT class. The
|
||||
default behavior of manual release via the COMThread class has been retained as
|
||||
the default behavior. Developers can test automatic memory collection by
|
||||
using the command line option <i>-Dcom.JACOB.autogc=true</i> </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>JNI Changes</b>
|
||||
<ul>
|
||||
|
||||
<li>Erroneous Array dimension checking fixed for certain boolean set and get functions
|
||||
</li>
|
||||
<li>Alternative method for finding Variant class for callbacks in JWS
|
||||
or other application lanchers where the system classloader does not
|
||||
know about JACOB classes. </li>
|
||||
<li>Unicode is supported for putString and putStringRef</li>
|
||||
<li>EventProxy zeros out the com object reference in the Variant objects
|
||||
that are created by EventProxy so that they are not double released,
|
||||
by both the Java VM and calling code from the COM side. The caller
|
||||
is supposed to be responsible for releasing the memory it created.
|
||||
This fix only applies to Variants created in callbacks. </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Logging Additions</b><ul>
|
||||
|
||||
<li>Debugging logging to standard out for JACOB can be turned on by using the
|
||||
command line option <i>-Dcom.JACOB.debug=true</i></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Visual Studio</b><ul>
|
||||
|
||||
<li>The VisualStudio directory in the CVS repository will be removed in the next
|
||||
release</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Documentation</b><ul>
|
||||
|
||||
<li>API documentation via Javadoc is now being generated for all classes.</li>
|
||||
|
||||
<li>The development team is looking for help in upgrading the quality of the
|
||||
class documentation</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Build Changes</b>
|
||||
<ul>
|
||||
|
||||
<li>A static method has been added to JacobObject that returns the build version</li>
|
||||
|
||||
<li>The project is now being built using ANT. Most of the developers are
|
||||
running this from inside of Eclipse</li>
|
||||
<li>All makefiles have been purged</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2>Tracked Changes</h2>
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td width="100%" colspan="2"><b>Bugs</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1116101</td>
|
||||
<td width="87%">jacob-msg 0284 : Access Violation while garbage collecting</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1114159</td>
|
||||
<td width="87%">Problem with COM Error Trapping in JACOB DLL</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1113610</td>
|
||||
<td width="87%">Bad error check in SafeArray.cpp</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1066698</td>
|
||||
<td width="87%">Minor Memory leak in Dispatch.cpp</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1065533</td>
|
||||
<td width="87%">Problem with unicode conversion</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1053871</td>
|
||||
<td width="87%">solution for memory leak in 1.7</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1053870</td>
|
||||
<td width="87%">JACOB0msg 2019 - Safe Array</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1053866</td>
|
||||
<td width="87%">getHResult only returns 80020009</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">960646</td>
|
||||
<td width="87%">But in SafeArray:: getBoolean for 2D arrays</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%"> </td>
|
||||
<td width="87%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" colspan="2"><b>Patches</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1115187</td>
|
||||
<td width="87%">EventCallbacks fail w/Variant ClassNotFoundException in JWS</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1105915</td>
|
||||
<td width="87%">Fix for event handling memory corruption</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1090104</td>
|
||||
<td width="87%">Weak Reference in teh ROT</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1068544</td>
|
||||
<td width="87%">in/out parameter support for event handlers</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">981540</td>
|
||||
<td width="87%">jre 1.4.2 fix as patch</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%"> </td>
|
||||
<td width="87%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" colspan="2"><b>Feature Requests</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1049390</td>
|
||||
<td width="87%">static Version information</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1049224</td>
|
||||
<td width="87%">Javadocs or at least script to generate it</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%">1049158</td>
|
||||
<td width="87%">API to get ProgId of ActiveXComponent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="13%"> </td>
|
||||
<td width="87%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h1>What's New in JACOB 1.8</H1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<b>Move To SourceForge</b>
|
||||
The project is not housed at
|
||||
<a href="http://sourceforge.net/projects/jacob-project/">Sourceforge.net</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Licensing Change</b>
|
||||
All limitations on commercial use of JACOB have been removed and it
|
||||
is now being developed under a BSD license at
|
||||
<a href="http://sourceforge.net/projects/jacob-project/">Sourceforge.net</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Compiled with Java 1.4.2</b>
|
||||
Version 1.8 was compiled with JSEE 1.4.2 and fixes the compilation bug
|
||||
that was remnant of compilation with JDK 1.1.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Baseline For Change</b>
|
||||
This version is the baseline for the first CVS checkin and we encourage
|
||||
people to start contributing to the project with this version.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<h1>What's New in JACOB 1.7</H1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<b>Explicit COM Threading Model Support:</b>
|
||||
See a detailed discussion of
|
||||
<a href="JacobThreading.html">COM Apartments in JACOB</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>New COM Object Lifetime model:</b>
|
||||
See a detailed discussion of
|
||||
<a href="JacobComLifetime.html">COM Object Lifetime in JACOB</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Improved Event Handling:</b>
|
||||
Thanks to code contributed by
|
||||
<a href="mailto:n.o.bouvin@daimi.au.dk">
|
||||
Niels Olof Bouvin</a>
|
||||
and <a href="mailto:jehoej@daimi.au.dk">Henning Jae</a> JACOB 1.7 can
|
||||
read the type information of a Connection Point interface by looking
|
||||
it up in the registry. This makes it possible to use events with IE as
|
||||
well as office products.
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<b>Improved Dispatch:</b>
|
||||
Error messages from Invoke failures are now printed out as well as
|
||||
allowing the passing in of arguments to a Get method.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>EnumVariant Implementation:</b>
|
||||
Makes it easier to iterate over COM collections. Thanks to code
|
||||
contributed by
|
||||
<a href="mailto:Thomas.Hallgren@eoncompany.com">Thomas Hallgren</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>SafeArray leaks:</b>
|
||||
SafeArrays were not being properly freed prior to version 1.7, many
|
||||
other memory leaks were fixed as well.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Visual Studio Project:</b>
|
||||
For those who want to debug: vstudio/JACOB. At the moment all the
|
||||
native code is replicated there from the jni directory...
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<H1>Related Links</H1>
|
||||
<ul>
|
||||
<li>
|
||||
The JACOB mailing list is hosted at yahoo groups:
|
||||
<a href="http://groups.yahoo.com/group/jacob-project">
|
||||
http://groups.yahoo.com/group/JACOB-project</a>.
|
||||
<b>This is the preferred way to get support for JACOB</b>. It also
|
||||
includes an extensive archive. If you are doing any development with
|
||||
JACOB, please join the list.
|
||||
<li>
|
||||
Massimiliano Bigatti has developed
|
||||
<a href="http://www.bigatti.it/projects/jacobgen/">
|
||||
JACOBgen - a generator that automatically creates JACOB code from
|
||||
Type Libraries</a>
|
||||
</li>
|
||||
<li>
|
||||
Steven Lewis is developing a version of Java2Com that supports JACOB
|
||||
code generation. See:
|
||||
<a href="http://www.lordjoe.com/Java2Com/index.html">
|
||||
http://www.lordjoe.com/Java2Com/index.html</a>.
|
||||
<li>
|
||||
To find documentation on the com.ms.com package, go to:
|
||||
<a href="http://www.microsoft.com/java/download/dl_sdk40.htm">
|
||||
http://www.microsoft.com/java/download/dl_sdk40.htm</a>
|
||||
and at the bottom of the page is a link that says:
|
||||
Microsoft SDK for Java 4.0 Documentation Only. You should download
|
||||
that file and install it. Then, view sdkdocs.chm and look for
|
||||
"Microsoft Packages Reference". Hopefully, the next release of
|
||||
JACOB will include full javadoc (volunteers?)...</li>
|
||||
3
docs/todo.txt
Normal file
3
docs/todo.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
1. Make everything check the current thread's mta-ness
|
||||
2. Write more documentation
|
||||
3. Get someone to help write the Javadoc
|
||||
4
jni/.cvsignore
Normal file
4
jni/.cvsignore
Normal file
@@ -0,0 +1,4 @@
|
||||
jacob.dll
|
||||
jacob.lib
|
||||
jacob.exp
|
||||
|
||||
@@ -410,9 +410,22 @@ JNIEXPORT jobject JNICALL Java_com_jacob_com_Dispatch_invokev
|
||||
|
||||
// check for error and display a somewhat verbose error message
|
||||
if (!SUCCEEDED(hr)) {
|
||||
const char *nm = env->GetStringUTFChars(name, NULL);
|
||||
char *buf = CreateErrorMsgFromInfo(hr, &excepInfo, nm);
|
||||
env->ReleaseStringUTFChars(name, nm);
|
||||
// two buffers that may have to be freed later
|
||||
char *buf = NULL;
|
||||
char *dispIdAsName = NULL;
|
||||
// this method can get called with a name or a dispatch id
|
||||
// we need to handle both SF 1114159
|
||||
if (name != NULL){
|
||||
const char *nm = env->GetStringUTFChars(name, NULL);
|
||||
buf = CreateErrorMsgFromInfo(hr, &excepInfo, nm);
|
||||
env->ReleaseStringUTFChars(name, nm);
|
||||
} else {
|
||||
dispIdAsName = new char[256];
|
||||
// get the id string
|
||||
itoa (dispID,dispIdAsName,10);
|
||||
//continue on mostly as before
|
||||
buf = CreateErrorMsgFromInfo(hr,&excepInfo,dispIdAsName);
|
||||
}
|
||||
|
||||
// jacob-msg 3696 - SF 1053866
|
||||
if(hr == DISP_E_EXCEPTION)
|
||||
@@ -429,6 +442,7 @@ JNIEXPORT jobject JNICALL Java_com_jacob_com_Dispatch_invokev
|
||||
|
||||
ThrowComFail(env, buf, hr);
|
||||
if (buf) delete buf;
|
||||
if (dispIdAsName) delete dispIdAsName;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,10 @@ void putProxy(JNIEnv *env, jobject arg, EventProxy *ep)
|
||||
* Signature: (LDispatch;Ljava/lang/Object;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init2
|
||||
(JNIEnv *env, jobject _this, jobject src, jobject sink, jstring _progid)
|
||||
(JNIEnv *env,
|
||||
jobject _this, jobject src,
|
||||
jobject sink, jobject protoVariant,
|
||||
jstring _progid)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
// find progid if any
|
||||
@@ -104,10 +107,11 @@ JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init2
|
||||
return;
|
||||
}
|
||||
HRESULT hr = pCPC->FindConnectionPoint(eventIID, &pCP);
|
||||
DWORD dwEventCookie;
|
||||
// VC++ 6.0 compiler realiized we weren't using this variable
|
||||
//DWORD dwEventCookie;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
EventProxy *ep = new EventProxy(env, sink, pCP, eventIID, mNames, mIDs, n_EventMethods);
|
||||
EventProxy *ep = new EventProxy(env, sink, protoVariant, pCP, eventIID, mNames, mIDs, n_EventMethods);
|
||||
// need to store ep on _this, in case it gets collected
|
||||
putProxy(env, _this, ep);
|
||||
} else {
|
||||
@@ -121,9 +125,9 @@ JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init2
|
||||
* Signature: (LDispatch;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init
|
||||
(JNIEnv *env, jobject _this, jobject src, jobject sink)
|
||||
(JNIEnv *env, jobject _this, jobject src, jobject sink, jobject protoVariant)
|
||||
{
|
||||
Java_com_jacob_com_DispatchEvents_init2(env,_this,src,sink,NULL);
|
||||
Java_com_jacob_com_DispatchEvents_init2(env,_this,src,sink, protoVariant, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -13,7 +13,7 @@ extern "C" {
|
||||
* Signature: (LDispatch;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init
|
||||
(JNIEnv *, jobject, jobject, jobject);
|
||||
(JNIEnv *, jobject, jobject, jobject, jobject);
|
||||
|
||||
/*
|
||||
* Class: DispatchEvents
|
||||
@@ -21,7 +21,7 @@ JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init
|
||||
* Signature: (LDispatch;Ljava/lang/Object;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_DispatchEvents_init2
|
||||
(JNIEnv *, jobject, jobject, jobject, jstring);
|
||||
(JNIEnv *, jobject, jobject, jobject, jobject, jstring);
|
||||
|
||||
/*
|
||||
* Class: DispatchEvents
|
||||
|
||||
@@ -28,34 +28,44 @@
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "EventProxy.h"
|
||||
#include "Variant.h"
|
||||
|
||||
// hook myself up as a listener for delegate
|
||||
EventProxy::EventProxy(JNIEnv *env, jobject aSinkObj,
|
||||
EventProxy::EventProxy(JNIEnv *env,
|
||||
jobject aSinkObj,
|
||||
jobject aVariantObj,
|
||||
CComPtr<IConnectionPoint> pConn,
|
||||
IID eid, CComBSTR mName[], DISPID mID[], int mNum) :
|
||||
IID eid,
|
||||
CComBSTR mName[],
|
||||
DISPID mID[],
|
||||
int mNum) :
|
||||
// initialize some variables
|
||||
m_cRef(0), pCP(pConn),
|
||||
eventIID(eid), MethNum(mNum), MethName(mName),
|
||||
MethID(mID), JMethID(NULL), javaSinkClass(NULL),
|
||||
variantClassMethod(NULL)
|
||||
MethID(mID), JMethID(NULL),
|
||||
javaSinkClass(NULL)
|
||||
{
|
||||
// don't really need the variant object but we keep a reference
|
||||
// anyway
|
||||
javaSinkObj = env->NewGlobalRef(aSinkObj);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe();}
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
javaVariantObj = env->NewGlobalRef(aVariantObj);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
|
||||
// we need this to attach to the event invocation thread
|
||||
env->GetJavaVM(&jvm);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
AddRef();
|
||||
HRESULT hr = pCP->Advise(this, &dwEventCookie);
|
||||
if (SUCCEEDED(hr)) {
|
||||
|
||||
// create a mapping from the DISPID's to jmethodID's by using
|
||||
// the method names I extracted from the classinfo
|
||||
JMethID = new jmethodID[MethNum];
|
||||
|
||||
javaSinkClass = env->GetObjectClass(javaSinkObj);
|
||||
if (javaSinkClass == NULL){ printf("can't figure out java sink class"); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
variantClassMethod = env->GetMethodID(javaSinkClass, "getVariantClass", "()Ljava/lang/Class;");
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (variantClassMethod == NULL) { printf("variantClassMethod == null\n"); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
|
||||
const char *method;
|
||||
for(int i=0;i<MethNum;i++)
|
||||
@@ -69,6 +79,7 @@ EventProxy::EventProxy(JNIEnv *env, jobject aSinkObj,
|
||||
// if the user didn't implement all the methods
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
} else {
|
||||
ThrowComFail(env, "Advise failed", hr);
|
||||
}
|
||||
@@ -85,10 +96,10 @@ EventProxy::~EventProxy()
|
||||
#else
|
||||
jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
env->DeleteGlobalRef(javaSinkObj);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
if (MethNum) {
|
||||
delete [] MethName;
|
||||
delete [] MethID;
|
||||
@@ -125,7 +136,8 @@ STDMETHODIMP EventProxy::Invoke(DISPID dispID, REFIID riid,
|
||||
LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams,
|
||||
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
|
||||
{
|
||||
HRESULT hr;
|
||||
//Visual C++ 6.0 recognized this as an unused variable
|
||||
//HRESULT hr;
|
||||
jmethodID meth = 0;
|
||||
JNIEnv *env = NULL;
|
||||
|
||||
@@ -146,29 +158,32 @@ STDMETHODIMP EventProxy::Invoke(DISPID dispID, REFIID riid,
|
||||
{
|
||||
// attach to the current running thread
|
||||
#ifdef JNI_VERSION_1_2
|
||||
jvm->AttachCurrentThread((void **)&env, jvm);
|
||||
#else
|
||||
jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
#endif
|
||||
jvm->AttachCurrentThread((void **)&env, jvm);
|
||||
#else
|
||||
jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
#endif
|
||||
|
||||
|
||||
// get variant class
|
||||
jclass vClass;
|
||||
jclass vClass = NULL;
|
||||
// do this in a JACOB 1.8 backwards compatable way
|
||||
// this succeeds if the class was loaded from the bootstrap class loader
|
||||
vClass = env->FindClass("com/jacob/com/Variant");
|
||||
//vClass = env->FindClass("com/jacob/com/Variant");
|
||||
// this is guarenteed to work so there really isn't any need for the line above
|
||||
// but I don't want to bust anything so we leave it in
|
||||
// the following code exists to support launchers like JWS where jacob isn't
|
||||
// in the system classloader so we wouldn't be able to create a variant class
|
||||
if (vClass == NULL){
|
||||
// see if our call back class implements our "special" method
|
||||
if (variantClassMethod != NULL){
|
||||
jobject variantFound = env->CallObjectMethod(javaSinkObj, variantClassMethod);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (variantFound == NULL) { printf("variantFound == null\n"); }
|
||||
vClass = (jclass)variantFound;
|
||||
} else {
|
||||
// dang they didn't. lets tell the user they are having a bad day
|
||||
printf("We're going to fail now in a way that is probably pretty ugly");
|
||||
// there will be a stored up exception if FindClass failed so lets clear it
|
||||
if (env->ExceptionOccurred()) { env->ExceptionClear(); }
|
||||
//printf("using variant class passed in via constructor\n");
|
||||
jclass javaVariantClass = env->GetObjectClass(javaVariantObj);
|
||||
if (javaVariantClass == NULL){ printf("can't figure out java Variant class"); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
vClass = javaVariantClass;
|
||||
if (vClass == NULL){
|
||||
printf("This application is probably running from a launcher where system class loader knows not Jacob\n");
|
||||
printf("The call back class does not implement 'Class getVariantClass()' that we can use to work around this\n");
|
||||
printf("And for some reason we couldn't find the variant class from the passed in variant\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,16 +191,16 @@ STDMETHODIMP EventProxy::Invoke(DISPID dispID, REFIID riid,
|
||||
int num = pDispParams->cArgs;
|
||||
// and the constructor
|
||||
jmethodID vCons = env->GetMethodID(vClass, "<init>", "()V");
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
// make an array of them
|
||||
jobjectArray varr = env->NewObjectArray(num, vClass, 0);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
int i,j;
|
||||
for(i=num-1,j=0;i>=0;i--,j++)
|
||||
{
|
||||
// construct a java variant holder
|
||||
jobject arg = env->NewObject(vClass, vCons);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
// get the empty variant from it
|
||||
VARIANT *va = extractVariant(env, arg);
|
||||
// copy the value
|
||||
@@ -193,11 +208,11 @@ STDMETHODIMP EventProxy::Invoke(DISPID dispID, REFIID riid,
|
||||
// put it in the array
|
||||
env->SetObjectArrayElement(varr, j, arg);
|
||||
env->DeleteLocalRef(arg);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
}
|
||||
// call the method
|
||||
env->CallVoidMethod(javaSinkObj, meth, varr);
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); }
|
||||
if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();}
|
||||
|
||||
|
||||
// Begin code from Jiffie team that copies parameters back from java to COM
|
||||
@@ -820,6 +835,7 @@ STDMETHODIMP EventProxy::Invoke(DISPID dispID, REFIID riid,
|
||||
|
||||
|
||||
}
|
||||
zeroVariant(env, arg);
|
||||
env->DeleteLocalRef(arg);
|
||||
}
|
||||
// End code from Jiffie team that copies parameters back from java to COM
|
||||
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
DWORD dwEventCookie; // connection point cookie
|
||||
jobject javaSinkObj; // the java object to delegate calls
|
||||
jclass javaSinkClass; // the java class of the object
|
||||
jmethodID variantClassMethod; // the method on the javaSinkObj that will return the Variant class
|
||||
jobject javaVariantObj; // a variant object passed in so we can find Variant later
|
||||
|
||||
IID eventIID; // the interface iid passed in
|
||||
int MethNum;
|
||||
@@ -70,9 +70,14 @@ private:
|
||||
public:
|
||||
// constuct with a global JNI ref to a sink object
|
||||
// to which we will delegate event callbacks
|
||||
EventProxy(JNIEnv *jenv, jobject aSinkObj,
|
||||
EventProxy(JNIEnv *jenv,
|
||||
jobject aSinkObj,
|
||||
jobject aVariantObj,
|
||||
CComPtr<IConnectionPoint> pConn,
|
||||
IID eventIID, CComBSTR *mName, DISPID *mID, int mNum);
|
||||
IID eventIID,
|
||||
CComBSTR *mName,
|
||||
DISPID *mID,
|
||||
int mNum);
|
||||
~EventProxy();
|
||||
|
||||
// IUnknown methods
|
||||
|
||||
@@ -99,13 +99,12 @@ SAFEARRAY *copySA(SAFEARRAY *psa)
|
||||
VARIANT v1, v2;
|
||||
|
||||
VariantInit(&v1);
|
||||
VariantInit(&v2);
|
||||
VariantInit(&v2);
|
||||
V_VT(&v1) = VT_ARRAY | vt;
|
||||
V_ARRAY(&v1) = psa;
|
||||
VariantCopy(&v2, &v1);
|
||||
SAFEARRAY *sa = V_ARRAY(&v2);
|
||||
VariantInit(&v2); // make sure it's not owned by this variant
|
||||
|
||||
VariantClear(&v2);
|
||||
VariantInit(&v1);
|
||||
VariantClear(&v1);
|
||||
@@ -1719,8 +1718,8 @@ JNIEXPORT void JNICALL Java_com_jacob_com_SafeArray_setString__IILjava_lang_Stri
|
||||
ThrowComFail(env, "safearray object corrupted", -1);
|
||||
return;
|
||||
}
|
||||
if (SafeArrayGetDim(sa) != 1) {
|
||||
ThrowComFail(env, "safearray is not 1D", -1);
|
||||
if (SafeArrayGetDim(sa) != 2) {
|
||||
ThrowComFail(env, "safearray is not 2D", -1);
|
||||
return;
|
||||
}
|
||||
VARTYPE vt;
|
||||
@@ -2035,8 +2034,8 @@ JNIEXPORT jboolean JNICALL Java_com_jacob_com_SafeArray_getBoolean__II
|
||||
ThrowComFail(env, "safearray object corrupted", -1);
|
||||
return NULL;
|
||||
}
|
||||
if (SafeArrayGetDim(sa) != 1) {
|
||||
ThrowComFail(env, "safearray is not 1D", -1);
|
||||
if (SafeArrayGetDim(sa) != 2) {
|
||||
ThrowComFail(env, "safearray is not 2D", -1);
|
||||
return NULL;
|
||||
}
|
||||
VARTYPE vt;
|
||||
@@ -2110,10 +2109,10 @@ JNIEXPORT void JNICALL Java_com_jacob_com_SafeArray_setBoolean__IIZ
|
||||
ThrowComFail(env, "safearray object corrupted", -1);
|
||||
return;
|
||||
}
|
||||
if (SafeArrayGetDim(sa) != 1) {
|
||||
ThrowComFail(env, "safearray is not 1D", -1);
|
||||
if (SafeArrayGetDim(sa) != 2) {
|
||||
ThrowComFail(env, "safearray is not 2D", -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
VARTYPE vt;
|
||||
SafeArrayGetVartype(sa, &vt);
|
||||
long idx[2] = {i,j};
|
||||
|
||||
@@ -91,6 +91,25 @@ JNIEXPORT void JNICALL Java_com_jacob_com_Variant_init
|
||||
env->SetIntField(_this, jf, (unsigned int)v);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: com_jacob_com_Variant
|
||||
* Method: zeroVariant
|
||||
* Signature: ()V
|
||||
*
|
||||
* This should only be used on variant objects created by teh
|
||||
* com layer as part of a call through EventProxy.
|
||||
* This zeros out the variant pointer in the Variant object
|
||||
* so that the calling COM program can free the memory.
|
||||
* instead of both the COM program and the Java GC doing it.
|
||||
*/
|
||||
void zeroVariant(JNIEnv *env, jobject _this)
|
||||
{
|
||||
jclass clazz = env->GetObjectClass(_this);
|
||||
jfieldID jf = env->GetFieldID(clazz, VARIANT_FLD, "I");
|
||||
env->SetIntField(_this, jf, (unsigned int)0);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_Variant_Save
|
||||
(JNIEnv *env, jobject _this, jobject outStream)
|
||||
{
|
||||
@@ -351,6 +370,7 @@ JNIEXPORT void JNICALL Java_com_jacob_com_Variant_putDateRef
|
||||
}
|
||||
}
|
||||
|
||||
// SF 1065533 added unicode support
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_Variant_putStringRef
|
||||
(JNIEnv *env, jobject _this, jstring s)
|
||||
{
|
||||
@@ -358,21 +378,15 @@ JNIEXPORT void JNICALL Java_com_jacob_com_Variant_putStringRef
|
||||
if (v) {
|
||||
VariantClear(v); // whatever was there before
|
||||
|
||||
// need to convert to C-style char buffer
|
||||
jclass strcls = env->FindClass("java/lang/String");
|
||||
jmethodID getBytes = env->GetMethodID(strcls, "getBytes", "()[B");
|
||||
jbyteArray ba = (jbyteArray)env->CallObjectMethod(s, getBytes);
|
||||
int len = env->GetArrayLength(ba);
|
||||
jbyte* buf = (jbyte*)alloca(len + 1);
|
||||
env->GetByteArrayRegion(ba, 0, len, buf);
|
||||
buf[len] = '\0';
|
||||
CComBSTR bs((char*)buf);
|
||||
const jchar *cStr = env->GetStringChars(s,NULL);
|
||||
CComBSTR bs(cStr);
|
||||
|
||||
BSTR *pbs = (BSTR *)CoTaskMemAlloc(sizeof(BSTR));
|
||||
bs.CopyTo(pbs);
|
||||
V_VT(v) = VT_BSTR|VT_BYREF;
|
||||
V_BSTRREF(v) = pbs;
|
||||
}
|
||||
|
||||
env->ReleaseStringChars(s,cStr); }
|
||||
}
|
||||
|
||||
JNIEXPORT jshort JNICALL Java_com_jacob_com_Variant_getShortRef
|
||||
@@ -858,6 +872,7 @@ JNIEXPORT jstring JNICALL Java_com_jacob_com_Variant_getString
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// SF 1065533 added unicode support
|
||||
JNIEXPORT void JNICALL Java_com_jacob_com_Variant_putString
|
||||
(JNIEnv *env, jobject _this, jstring s)
|
||||
{
|
||||
@@ -866,18 +881,13 @@ JNIEXPORT void JNICALL Java_com_jacob_com_Variant_putString
|
||||
VariantClear(v); // whatever was there before
|
||||
V_VT(v) = VT_BSTR;
|
||||
|
||||
// get C-style byte array
|
||||
jclass strcls = env->FindClass("java/lang/String");
|
||||
jmethodID getBytes = env->GetMethodID(strcls, "getBytes", "()[B");
|
||||
jbyteArray ba = (jbyteArray)env->CallObjectMethod(s, getBytes);
|
||||
int len = env->GetArrayLength(ba);
|
||||
jbyte* buf = (jbyte*)alloca(len + 1);
|
||||
env->GetByteArrayRegion(ba, 0, len, buf);
|
||||
buf[len] = '\0';
|
||||
const jchar *cStr = env->GetStringChars(s,NULL);
|
||||
CComBSTR bs(cStr);
|
||||
|
||||
CComBSTR bs((char*)buf);
|
||||
V_VT(v) = VT_BSTR;
|
||||
V_BSTR(v) = bs.Copy();
|
||||
|
||||
env->ReleaseStringChars(s,cStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -607,6 +607,19 @@ JNIEXPORT void JNICALL Java_com_jacob_com_Variant_Load
|
||||
JNIEXPORT jboolean JNICALL Java_com_jacob_com_Variant_isNull
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_jacob_com_Variant
|
||||
* Method: zeroVariant
|
||||
* Signature: ()V
|
||||
*
|
||||
* This should only be used on variant objects created by teh
|
||||
* com layer as part of a call through EventProxy.
|
||||
* This zeros out the variant pointer in the Variant object
|
||||
* so that the calling COM program can free the memory.
|
||||
* instead of both the COM program and the Java GC doing it.
|
||||
*/
|
||||
void zeroVariant (JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
BIN
jni/jacob.dll
BIN
jni/jacob.dll
Binary file not shown.
BIN
jni/jacob.exp
BIN
jni/jacob.exp
Binary file not shown.
BIN
jni/jacob.lib
BIN
jni/jacob.lib
Binary file not shown.
51
jni/makefile
51
jni/makefile
@@ -1,51 +0,0 @@
|
||||
JDK = d:\j2sdk1.4.2_06
|
||||
DEST_DIR = d:\jacob_18
|
||||
MSDEVDIR = d:\apps\\"Microsoft Visual Studio"\VC98
|
||||
|
||||
JDK_INC = -I$(JDK)\include -I$(JDK)\include\win32
|
||||
JDK_LIB = $(JDK)\lib\jvm.lib
|
||||
MS_INC = -I$(MSDEVDIR)\Include -I$(MSDEVDIR)\ATL\Include
|
||||
SYS_LIB = oleaut32.lib ole32.lib uuid.lib kernel32.lib shell32.lib user32.lib
|
||||
OPT = /O2
|
||||
CC = cl $(OPT) $(JDK_INC) $(MS_INC)
|
||||
|
||||
OBJFILES = stdafx.obj util.obj EventProxy.obj Variant.obj Dispatch.obj SafeArray.obj DispatchEvents.obj ComThread.obj EnumVariant.obj STA.obj DispatchProxy.obj
|
||||
|
||||
all: jacob.dll
|
||||
cp jacob.dll $(DEST_DIR)
|
||||
|
||||
jacob.dll: $(OBJFILES)
|
||||
link /dll /out:jacob.dll $(OBJFILES) $(JDK_LIB) $(SYS_LIB)
|
||||
|
||||
stdafx.obj: stdafx.cpp *.h
|
||||
$(CC) -c stdafx.cpp
|
||||
|
||||
util.obj: util.cpp *.h
|
||||
$(CC) -c util.cpp
|
||||
|
||||
EventProxy.obj: EventProxy.cpp *.h
|
||||
$(CC) -c EventProxy.cpp
|
||||
|
||||
Variant.obj: Variant.cpp *.h
|
||||
$(CC) -c Variant.cpp
|
||||
|
||||
Dispatch.obj: Dispatch.cpp *.h
|
||||
$(CC) -c Dispatch.cpp
|
||||
|
||||
SafeArray.obj: SafeArray.cpp *.h
|
||||
$(CC) -c SafeArray.cpp
|
||||
|
||||
DispatchEvents.obj: DispatchEvents.cpp *.h
|
||||
$(CC) -c DispatchEvents.cpp
|
||||
|
||||
ComThread.obj: ComThread.cpp *.h
|
||||
$(CC) -c ComThread.cpp
|
||||
|
||||
EnumVariant.obj: EnumVariant.cpp *.h
|
||||
$(CC) -c EnumVariant.cpp
|
||||
|
||||
STA.obj: STA.cpp *.h
|
||||
$(CC) -c STA.cpp
|
||||
|
||||
DispatchProxy.obj: DispatchProxy.cpp *.h
|
||||
$(CC) -c DispatchProxy.cpp
|
||||
@@ -5,6 +5,5 @@ extern "C" {
|
||||
IDispatch *extractDispatch(JNIEnv *env, jobject arg);
|
||||
SAFEARRAY *extractSA(JNIEnv *env, jobject arg);
|
||||
void setSA(JNIEnv *env, jobject arg, SAFEARRAY *sa, int copy);
|
||||
|
||||
SAFEARRAY *copySA(SAFEARRAY *psa)
|
||||
SAFEARRAY *copySA(SAFEARRAY *psa);
|
||||
}
|
||||
|
||||
18
makefile
18
makefile
@@ -1,18 +0,0 @@
|
||||
JAVAC = d:\j2sdk1.4.2_06\bin\javac -O
|
||||
JAR = d:\j2sdk1.4.2_06\bin\jar -cvf jacob.jar
|
||||
COM_DIR = com\jacob\com
|
||||
ACX_DIR = com\jacob\activeX
|
||||
|
||||
all: java jni
|
||||
rm -f jacobSrc_18.zip jacobBin_18.zip
|
||||
jar -cvf jacobSrc_18.zip .
|
||||
jar -cvf jacobBin_18.zip jacob.dll jacob.jar LICENSE.TXT README.TXT samples
|
||||
|
||||
java: jacob.jar
|
||||
$(JAVAC) $(COM_DIR)\*.java $(ACX_DIR)\*.java
|
||||
$(JAR) $(COM_DIR)\*.class $(ACX_DIR)\*.class
|
||||
|
||||
jni: jni\jacob.dll
|
||||
cd jni
|
||||
nmake -f makefile all
|
||||
cd ..\
|
||||
@@ -1,88 +1,88 @@
|
||||
- ADO Wrapper for JACOB - Copyright 1999, Dan Adler
|
||||
|
||||
This sample shows how to generate more strongly typed wrapper classes
|
||||
for the JACOB automation classes. These are pure java classes which
|
||||
extend com.jacob.com.Dispatch and delegate all the methods to the
|
||||
unedrlying IDispatch pointer. This methodology is similar to the way
|
||||
MFC does automation wrappers, rather than using the @com directives
|
||||
to invisibly delegate the calls, as the Microsoft VM does.
|
||||
|
||||
The ADO wrappers in this directory are not a part of the JACOB
|
||||
distribution, however, they demonstrate the preferred way to create
|
||||
wrappers around the core functionality. The wrappers included here are
|
||||
not a complete set, but they could easily be extended to provide all
|
||||
the functionality of the com.ms.wfc.data classes.
|
||||
|
||||
The code in test.java demonstrates two ways to get a Recordset
|
||||
from SQL Server. In this case, I query for the authors in the 'pubs'
|
||||
database once by opening a Recordset object directly, and once by
|
||||
using the Command and Connection objects. The same code, using the WFC
|
||||
wrappers can be found in ms\testms.java in case you want to compare
|
||||
the performace. You can run the test.java demo in the MS VM as well.
|
||||
|
||||
The constructor of the wrapper is used to create an instance.
|
||||
For example, the user can write:
|
||||
|
||||
Connection c = new Connection();
|
||||
|
||||
The code for the Connection constructor is shown here:
|
||||
|
||||
public Connection()
|
||||
{
|
||||
super("ADODB.Connection");
|
||||
}
|
||||
|
||||
it simply delegates to the com.jacob.com.Dispatch constructor which
|
||||
takes a ProgID.
|
||||
|
||||
Since I don't have a tool like JACTIVEX yet to create the wrappers
|
||||
automatically from the type library, I created them by hand by using
|
||||
the JACTIVEX'ed version as a starting point, and replacing the @com
|
||||
calls with delegated calls to JACOB classes. A simple PERL program
|
||||
could probably be used to automate this step.
|
||||
|
||||
In order to return strongly typed wrappers from method calls, I had to
|
||||
create a special constructor which constructs the wrapper class instance
|
||||
and copies over the IDispatch pointer. This is because I can't cast a
|
||||
java Dispatch object to a super class object.
|
||||
|
||||
For example, the Command class has a method like this:
|
||||
|
||||
public Connection getActiveConnection();
|
||||
|
||||
Ideally, I would like the wrapper code to say:
|
||||
|
||||
public Connection getActiveConnection()
|
||||
{
|
||||
// this doesn't work
|
||||
return (Connection)Dispatch.get(this, "ActiveConnection").toDispatch());
|
||||
}
|
||||
|
||||
Thereby wrapping the returned Dispatch pointer in a Connection object.
|
||||
But, since I can't cast in this way, I use the following construct:
|
||||
|
||||
public Connection getActiveConnection()
|
||||
{
|
||||
// this works
|
||||
return new Connection(Dispatch.get(this, "ActiveConnection").toDispatch());
|
||||
}
|
||||
|
||||
Which uses a special constructor inserted into the Connection class:
|
||||
|
||||
/**
|
||||
* This constructor is used instead of a case operation to
|
||||
* turn a Dispatch object into a wider object - it must exist
|
||||
* in every wrapper class whose instances may be returned from
|
||||
* method calls wrapped in VT_DISPATCH Variants.
|
||||
*/
|
||||
public Connection(Dispatch d)
|
||||
{
|
||||
// take over the IDispatch pointer
|
||||
m_pDispatch = d.m_pDispatch;
|
||||
// null out the input's pointer
|
||||
d.m_pDispatch = 0;
|
||||
}
|
||||
|
||||
I have to add this constructor to any class whose instances I want
|
||||
to return from wrapped calls.
|
||||
|
||||
- ADO Wrapper for JACOB - Copyright 1999, Dan Adler
|
||||
|
||||
This sample shows how to generate more strongly typed wrapper classes
|
||||
for the JACOB automation classes. These are pure java classes which
|
||||
extend com.jacob.com.Dispatch and delegate all the methods to the
|
||||
unedrlying IDispatch pointer. This methodology is similar to the way
|
||||
MFC does automation wrappers, rather than using the @com directives
|
||||
to invisibly delegate the calls, as the Microsoft VM does.
|
||||
|
||||
The ADO wrappers in this directory are not a part of the JACOB
|
||||
distribution, however, they demonstrate the preferred way to create
|
||||
wrappers around the core functionality. The wrappers included here are
|
||||
not a complete set, but they could easily be extended to provide all
|
||||
the functionality of the com.ms.wfc.data classes.
|
||||
|
||||
The code in test.java demonstrates two ways to get a Recordset
|
||||
from SQL Server. In this case, I query for the authors in the 'pubs'
|
||||
database once by opening a Recordset object directly, and once by
|
||||
using the Command and Connection objects. The same code, using the WFC
|
||||
wrappers can be found in ms\testms.java in case you want to compare
|
||||
the performace. You can run the test.java demo in the MS VM as well.
|
||||
|
||||
The constructor of the wrapper is used to create an instance.
|
||||
For example, the user can write:
|
||||
|
||||
Connection c = new Connection();
|
||||
|
||||
The code for the Connection constructor is shown here:
|
||||
|
||||
public Connection()
|
||||
{
|
||||
super("ADODB.Connection");
|
||||
}
|
||||
|
||||
it simply delegates to the com.jacob.com.Dispatch constructor which
|
||||
takes a ProgID.
|
||||
|
||||
Since I don't have a tool like JACTIVEX yet to create the wrappers
|
||||
automatically from the type library, I created them by hand by using
|
||||
the JACTIVEX'ed version as a starting point, and replacing the @com
|
||||
calls with delegated calls to JACOB classes. A simple PERL program
|
||||
could probably be used to automate this step.
|
||||
|
||||
In order to return strongly typed wrappers from method calls, I had to
|
||||
create a special constructor which constructs the wrapper class instance
|
||||
and copies over the IDispatch pointer. This is because I can't cast a
|
||||
java Dispatch object to a super class object.
|
||||
|
||||
For example, the Command class has a method like this:
|
||||
|
||||
public Connection getActiveConnection();
|
||||
|
||||
Ideally, I would like the wrapper code to say:
|
||||
|
||||
public Connection getActiveConnection()
|
||||
{
|
||||
// this doesn't work
|
||||
return (Connection)Dispatch.get(this, "ActiveConnection").toDispatch());
|
||||
}
|
||||
|
||||
Thereby wrapping the returned Dispatch pointer in a Connection object.
|
||||
But, since I can't cast in this way, I use the following construct:
|
||||
|
||||
public Connection getActiveConnection()
|
||||
{
|
||||
// this works
|
||||
return new Connection(Dispatch.get(this, "ActiveConnection").toDispatch());
|
||||
}
|
||||
|
||||
Which uses a special constructor inserted into the Connection class:
|
||||
|
||||
/**
|
||||
* This constructor is used instead of a case operation to
|
||||
* turn a Dispatch object into a wider object - it must exist
|
||||
* in every wrapper class whose instances may be returned from
|
||||
* method calls wrapped in VT_DISPATCH Variants.
|
||||
*/
|
||||
public Connection(Dispatch d)
|
||||
{
|
||||
// take over the IDispatch pointer
|
||||
m_pDispatch = d.m_pDispatch;
|
||||
// null out the input's pointer
|
||||
d.m_pDispatch = 0;
|
||||
}
|
||||
|
||||
I have to add this constructor to any class whose instances I want
|
||||
to return from wrapped calls.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
|
||||
// Enum: CommandTypeEnum
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
import com.jacob.com.*;
|
||||
|
||||
public class Field extends Dispatch
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
import com.jacob.com.*;
|
||||
|
||||
public class Fields extends Dispatch
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
import com.jacob.com.*;
|
||||
|
||||
public class Recordset extends Dispatch
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.ado;
|
||||
package com.jacob.samples.ado;
|
||||
import com.jacob.com.*;
|
||||
|
||||
public class test
|
||||
@@ -1,8 +1,8 @@
|
||||
<title>Applet Test (1.1)</title>
|
||||
<h1>Applet Test (1.1)</h1>
|
||||
<hr>
|
||||
<applet code=AppTest.class width=400 height=400>
|
||||
</applet>
|
||||
<hr>
|
||||
<a href="AppTest.java">The source.</a>
|
||||
<br>
|
||||
<title>Applet Test (1.1)</title>
|
||||
<h1>Applet Test (1.1)</h1>
|
||||
<hr>
|
||||
<applet code=AppTest.class width=400 height=400>
|
||||
</applet>
|
||||
<hr>
|
||||
<a href="AppTest.java">The source.</a>
|
||||
<br>
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.applet;
|
||||
package com.jacob.samples.applet;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
@@ -16,7 +16,7 @@ public class AppTest extends Applet implements ActionListener
|
||||
TextField out;
|
||||
Button calc;
|
||||
ActiveXComponent sC = null;
|
||||
Object sControl = null;
|
||||
Dispatch sControl = null;
|
||||
|
||||
/**
|
||||
* startup method
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.servlet;
|
||||
package com.jacob.samples.servlet;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
@@ -44,7 +44,7 @@ public class JacobScript extends javax.servlet.http.HttpServlet
|
||||
String expr = (String)req.getParameter("expr");
|
||||
// make sure we have a session
|
||||
HttpSession session = req.getSession(true);
|
||||
Object sControl = null;
|
||||
Dispatch sControl = null;
|
||||
if (session.isNew())
|
||||
{
|
||||
// initialize the control and store it on the session
|
||||
@@ -56,7 +56,7 @@ public class JacobScript extends javax.servlet.http.HttpServlet
|
||||
}
|
||||
else
|
||||
{
|
||||
sControl = session.getValue("control");
|
||||
sControl = (Dispatch)session.getValue("control");
|
||||
}
|
||||
Variant result = Dispatch.call(sControl, "Eval", expr);
|
||||
// display a form
|
||||
@@ -1,44 +1,44 @@
|
||||
This sample runs in Weblogic 5.1 as a servlet.
|
||||
|
||||
1. Compile this file (make sure you have jdk1.2 installed or the
|
||||
javax.servlet.* classes in your classpath).
|
||||
2. Make sure the weblogic policy file allows native access. The easiest
|
||||
way is to replace the contents with this:
|
||||
|
||||
grant codeBase "file:d:/weblogic/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant codeBase "file:/c:/classes/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
|
||||
grant codeBase "file:${java.home}/lib/ext/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
3. Add the servlet to the weblogic.properties file:
|
||||
|
||||
weblogic.httpd.register.JacobScript=JacobScript
|
||||
|
||||
4. Either add your CLASSPATH to weblogic.classpath in startWebLogic.cmd
|
||||
or copy the com directory into weblogic/myserver/servletclasses
|
||||
|
||||
5. Copy the jacob/samples/servlet/* into weblogic/myserver/servletclasses
|
||||
6. Start weblogic
|
||||
|
||||
7. Type the url: http://localhost:7001/JacobScript into the browser
|
||||
(If you run on port 7001)
|
||||
|
||||
8. Enter a VBScript expression like:
|
||||
1+2
|
||||
Now
|
||||
"hello" & " world"
|
||||
etc.
|
||||
and watch the MS Script control (which you must have installed)
|
||||
evaluate and return the result.
|
||||
This sample runs in Weblogic 5.1 as a servlet.
|
||||
|
||||
1. Compile this file (make sure you have jdk1.2 installed or the
|
||||
javax.servlet.* classes in your classpath).
|
||||
2. Make sure the weblogic policy file allows native access. The easiest
|
||||
way is to replace the contents with this:
|
||||
|
||||
grant codeBase "file:d:/weblogic/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant codeBase "file:/c:/classes/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
|
||||
grant codeBase "file:${java.home}/lib/ext/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
3. Add the servlet to the weblogic.properties file:
|
||||
|
||||
weblogic.httpd.register.JacobScript=JacobScript
|
||||
|
||||
4. Either add your CLASSPATH to weblogic.classpath in startWebLogic.cmd
|
||||
or copy the com directory into weblogic/myserver/servletclasses
|
||||
|
||||
5. Copy the jacob/samples/servlet/* into weblogic/myserver/servletclasses
|
||||
6. Start weblogic
|
||||
|
||||
7. Type the url: http://localhost:7001/JacobScript into the browser
|
||||
(If you run on port 7001)
|
||||
|
||||
8. Enter a VBScript expression like:
|
||||
1+2
|
||||
Now
|
||||
"hello" & " world"
|
||||
etc.
|
||||
and watch the MS Script control (which you must have installed)
|
||||
evaluate and return the result.
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.test;
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
@@ -1,40 +1,40 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class DispatchTest
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
ComThread.InitSTA();
|
||||
|
||||
ActiveXComponent xl = new ActiveXComponent("Excel.Application");
|
||||
Object xlo = xl.getObject();
|
||||
try {
|
||||
System.out.println("version="+xl.getProperty("Version"));
|
||||
System.out.println("version="+Dispatch.get(xlo, "Version"));
|
||||
Dispatch.put(xlo, "Visible", new Variant(true));
|
||||
Object workbooks = xl.getProperty("Workbooks").toDispatch();
|
||||
Object workbook = Dispatch.get(workbooks,"Add").toDispatch();
|
||||
Object sheet = Dispatch.get(workbook,"ActiveSheet").toDispatch();
|
||||
Object a1 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
|
||||
new Object[] {"A1"},
|
||||
new int[1]).toDispatch();
|
||||
Object a2 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
|
||||
new Object[] {"A2"},
|
||||
new int[1]).toDispatch();
|
||||
Dispatch.put(a1, "Value", "123.456");
|
||||
Dispatch.put(a2, "Formula", "=A1*2");
|
||||
System.out.println("a1 from excel:"+Dispatch.get(a1, "Value"));
|
||||
System.out.println("a2 from excel:"+Dispatch.get(a2, "Value"));
|
||||
Variant f = new Variant(false);
|
||||
Dispatch.call(workbook, "Close", f);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
xl.invoke("Quit", new Variant[] {});
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class DispatchTest
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
ComThread.InitSTA();
|
||||
|
||||
ActiveXComponent xl = new ActiveXComponent("Excel.Application");
|
||||
Dispatch xlo = xl.getObject();
|
||||
try {
|
||||
System.out.println("version="+xl.getProperty("Version"));
|
||||
System.out.println("version="+Dispatch.get(xlo, "Version"));
|
||||
Dispatch.put(xlo, "Visible", new Variant(true));
|
||||
Dispatch workbooks = xl.getProperty("Workbooks").toDispatch();
|
||||
Dispatch workbook = Dispatch.get(workbooks,"Add").toDispatch();
|
||||
Dispatch sheet = Dispatch.get(workbook,"ActiveSheet").toDispatch();
|
||||
Dispatch a1 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
|
||||
new Object[] {"A1"},
|
||||
new int[1]).toDispatch();
|
||||
Dispatch a2 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
|
||||
new Object[] {"A2"},
|
||||
new int[1]).toDispatch();
|
||||
Dispatch.put(a1, "Value", "123.456");
|
||||
Dispatch.put(a2, "Formula", "=A1*2");
|
||||
System.out.println("a1 from excel:"+Dispatch.get(a1, "Value"));
|
||||
System.out.println("a2 from excel:"+Dispatch.get(a2, "Value"));
|
||||
Variant f = new Variant(false);
|
||||
Dispatch.call(workbook, "Close", f);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
xl.invoke("Quit", new Variant[] {});
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.test;
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
@@ -14,8 +14,9 @@ class IETest
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
int delay = 5000; // msec
|
||||
ActiveXComponent ie = new ActiveXComponent("clsid:0002DF01-0000-0000-C000-000000000046");
|
||||
Object ieo = ie.getObject();
|
||||
Dispatch ieo = ie.getObject();
|
||||
try {
|
||||
Dispatch.put(ieo, "Visible", new Variant(true));
|
||||
Dispatch.put(ieo, "AddressBar", new Variant(true));
|
||||
@@ -28,9 +29,9 @@ class IETest
|
||||
optional.noParam();
|
||||
|
||||
Dispatch.call(ieo, "Navigate", new Variant("http://www.danadler.com/jacob"));
|
||||
try { Thread.sleep(5000); } catch (Exception e) {}
|
||||
try { Thread.sleep(delay); } catch (Exception e) {}
|
||||
Dispatch.call(ieo, "Navigate", new Variant("http://groups.yahoo.com/group/jacob-project"));
|
||||
try { Thread.sleep(5000); } catch (Exception e) {}
|
||||
try { Thread.sleep(delay); } catch (Exception e) {}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.test;
|
||||
package com.jacob.samples.test;
|
||||
|
||||
/**
|
||||
* JACOB Outlook sample contributed by
|
||||
@@ -22,14 +22,14 @@ public class Outlook {
|
||||
}
|
||||
|
||||
|
||||
private static void recurseFolders(int iIndent, Object o) {
|
||||
private static void recurseFolders(int iIndent, Dispatch o) {
|
||||
|
||||
if (o == null) return;
|
||||
Object oFolders = Dispatch.get(o, "Folders").toDispatch();
|
||||
Dispatch oFolders = Dispatch.get(o, "Folders").toDispatch();
|
||||
// System.out.println("oFolders=" + oFolders);
|
||||
if (oFolders == null) return;
|
||||
|
||||
Object oFolder = Dispatch.get(oFolders, "GetFirst").toDispatch();
|
||||
Dispatch oFolder = Dispatch.get(oFolders, "GetFirst").toDispatch();
|
||||
do {
|
||||
Object oFolderName = Dispatch.get(oFolder, "Name");
|
||||
if (null == oFolderName) {
|
||||
@@ -52,10 +52,10 @@ public class Outlook {
|
||||
try {
|
||||
System.out.println("version="+axOutlook.getProperty("Version"));
|
||||
|
||||
Object oOutlook = axOutlook.getObject();
|
||||
Dispatch oOutlook = axOutlook.getObject();
|
||||
System.out.println("version="+Dispatch.get(oOutlook, "Version"));
|
||||
|
||||
Object oNameSpace = axOutlook.getProperty("Session").toDispatch();
|
||||
Dispatch oNameSpace = axOutlook.getProperty("Session").toDispatch();
|
||||
System.out.println("oNameSpace=" + oNameSpace);
|
||||
|
||||
recurseFolders(0, oNameSpace);
|
||||
@@ -1,57 +1,47 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* In this case the component is created and used in the same thread
|
||||
* and it's an Apartment Threaded component, so we call InitSTA.
|
||||
*/
|
||||
class ScriptTest
|
||||
{
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
ComThread.InitSTA(true);
|
||||
DispatchEvents de = null;
|
||||
Dispatch sControl = null;
|
||||
|
||||
try {
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
sControl = (Dispatch)sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
errEvents te = new errEvents();
|
||||
de = new DispatchEvents(sControl, te);
|
||||
Variant result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
// call it twice to see the objects reused
|
||||
result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
// call it 3 times to see the objects reused
|
||||
result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Integer I = null;
|
||||
for(int i=1;i<1000000;i++)
|
||||
{
|
||||
I = new Integer(i);
|
||||
}
|
||||
System.out.println(I);
|
||||
ComThread.Release();
|
||||
ComThread.quitMainSTA();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class errEvents {
|
||||
public void Error(Variant[] args)
|
||||
{
|
||||
System.out.println("java callback for error!");
|
||||
}
|
||||
public void Timeout(Variant[] args)
|
||||
{
|
||||
System.out.println("java callback for error!");
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* In this case the component is created and used in the same thread
|
||||
* and it's an Apartment Threaded component, so we call InitSTA.
|
||||
*/
|
||||
class ScriptTest
|
||||
{
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
ComThread.InitSTA(true);
|
||||
DispatchEvents de = null;
|
||||
Dispatch sControl = null;
|
||||
|
||||
try {
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
sControl = (Dispatch)sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
ScriptTestErrEvents te = new ScriptTestErrEvents();
|
||||
de = new DispatchEvents(sControl, te);
|
||||
Variant result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
// call it twice to see the objects reused
|
||||
result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
// call it 3 times to see the objects reused
|
||||
result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Integer I = null;
|
||||
for(int i=1;i<1000000;i++)
|
||||
{
|
||||
I = new Integer(i);
|
||||
}
|
||||
System.out.println(I);
|
||||
ComThread.Release();
|
||||
ComThread.quitMainSTA();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* This example demonstrates how to make calls between
|
||||
* two different STA's.
|
||||
* First, to create an STA, you need to extend the STA class
|
||||
* and override its OnInit() method. This method will be called
|
||||
* in the STA's thread so you can use it to create your COM
|
||||
* components that will run in that STA.
|
||||
* If you then try to call methods on those components from other
|
||||
* threads (STA or MTA) - this will fail.
|
||||
* You cannot create a component in an STA and call its methods
|
||||
* from another thread.
|
||||
* You can use the DispatchProxy to get a proxy to any Dispatch
|
||||
* that lives in another STA. This object has to be created in the
|
||||
* STA that houses the Dispatch (in this case it's created in the
|
||||
* OnInit method). Then, another thread can call the toDispatch()
|
||||
* method of DispatchProxy to get a local proxy. At most ONE (!)
|
||||
* thread can call toDispatch(), and the call can be made only once.
|
||||
* This is because a IStream object is used to pass the proxy, and
|
||||
* it is only written once and closed when you read it.
|
||||
* If you need multiple threads to access a Dispatch pointer, then
|
||||
* create that many DispatchProxy objects.
|
||||
*/
|
||||
class ScriptTest2 extends STA
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static DispatchEvents de = null;
|
||||
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);
|
||||
errEvents te = new errEvents();
|
||||
de = new DispatchEvents(sControl, te);
|
||||
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
|
||||
{
|
||||
Integer I = null;
|
||||
for(int i=1;i<1000000;i++)
|
||||
{
|
||||
I = new Integer(i);
|
||||
}
|
||||
System.out.println(I);
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* This example demonstrates how to make calls between
|
||||
* two different STA's.
|
||||
* First, to create an STA, you need to extend the STA class
|
||||
* and override its OnInit() method. This method will be called
|
||||
* in the STA's thread so you can use it to create your COM
|
||||
* components that will run in that STA.
|
||||
* If you then try to call methods on those components from other
|
||||
* threads (STA or MTA) - this will fail.
|
||||
* You cannot create a component in an STA and call its methods
|
||||
* from another thread.
|
||||
* You can use the DispatchProxy to get a proxy to any Dispatch
|
||||
* that lives in another STA. This object has to be created in the
|
||||
* STA that houses the Dispatch (in this case it's created in the
|
||||
* OnInit method). Then, another thread can call the toDispatch()
|
||||
* method of DispatchProxy to get a local proxy. At most ONE (!)
|
||||
* thread can call toDispatch(), and the call can be made only once.
|
||||
* This is because a IStream object is used to pass the proxy, and
|
||||
* it is only written once and closed when you read it.
|
||||
* If you need multiple threads to access a Dispatch pointer, then
|
||||
* create that many DispatchProxy objects.
|
||||
*/
|
||||
class ScriptTest2 extends STA
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static DispatchEvents de = null;
|
||||
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);
|
||||
ScriptTestErrEvents te = new ScriptTestErrEvents();
|
||||
de = new DispatchEvents(sControl, te);
|
||||
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
|
||||
{
|
||||
Integer I = null;
|
||||
for(int i=1;i<1000000;i++)
|
||||
{
|
||||
I = new Integer(i);
|
||||
}
|
||||
System.out.println(I);
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
96
samples/com/jacob/samples/test/ScriptTest2ActiveX.java
Normal file
96
samples/com/jacob/samples/test/ScriptTest2ActiveX.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* This example demonstrates how to make calls between
|
||||
* two different STA's.
|
||||
* First, to create an STA, you need to extend the STA class
|
||||
* and override its OnInit() method. This method will be called
|
||||
* in the STA's thread so you can use it to create your COM
|
||||
* components that will run in that STA.
|
||||
* If you then try to call methods on those components from other
|
||||
* threads (STA or MTA) - this will fail.
|
||||
* You cannot create a component in an STA and call its methods
|
||||
* from another thread.
|
||||
* You can use the DispatchProxy to get a proxy to any Dispatch
|
||||
* that lives in another STA. This object has to be created in the
|
||||
* STA that houses the Dispatch (in this case it's created in the
|
||||
* OnInit method). Then, another thread can call the toDispatch()
|
||||
* method of DispatchProxy to get a local proxy. At most ONE (!)
|
||||
* thread can call toDispatch(), and the call can be made only once.
|
||||
* This is because a IStream object is used to pass the proxy, and
|
||||
* it is only written once and closed when you read it.
|
||||
* If you need multiple threads to access a Dispatch pointer, then
|
||||
* create that many DispatchProxy objects.
|
||||
*/
|
||||
class ScriptTest2ActiveX extends STA
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static DispatchEvents de = 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");
|
||||
|
||||
// sCon can be called from another thread
|
||||
sCon = new DispatchProxy(sC);
|
||||
|
||||
sC.setProperty("Language", lang);
|
||||
ScriptTestErrEvents te = new ScriptTestErrEvents();
|
||||
de = new DispatchEvents(sC, te);
|
||||
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();
|
||||
ScriptTest2ActiveX script = new ScriptTest2ActiveX();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// get a thread-local Dispatch from sCon
|
||||
ActiveXComponent sc = new ActiveXComponent(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 = sc.invoke("Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
script.quit();
|
||||
System.out.println("called quit");
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Integer I = null;
|
||||
for(int i=1;i<1000000;i++)
|
||||
{
|
||||
I = new Integer(i);
|
||||
}
|
||||
System.out.println(I);
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,68 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* Here we create the ScriptControl component in a separate MTA thread
|
||||
* and then call the Eval method from the main thread. The main thread
|
||||
* must also be an MTA thread. If you try to create it as an STA
|
||||
* then you will not be able to make calls into a component running
|
||||
* in another thread.
|
||||
*/
|
||||
class ScriptTest3 extends Thread
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static DispatchEvents de = null;
|
||||
public static Dispatch sControl = null;
|
||||
public static boolean quit = false;
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
ComThread.InitMTA();
|
||||
System.out.println("OnInit");
|
||||
String lang = "VBScript";
|
||||
sC = new ActiveXComponent("ScriptControl");
|
||||
sControl = (Dispatch)sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
errEvents te = new errEvents();
|
||||
de = new DispatchEvents(sControl, te);
|
||||
System.out.println("sControl="+sControl);
|
||||
while (!quit) sleep(100);
|
||||
ComThread.Release();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.out.println("worker thread exits");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
try {
|
||||
ComThread.InitMTA();
|
||||
ScriptTest3 script = new ScriptTest3();
|
||||
script.start();
|
||||
Thread.sleep(1000);
|
||||
|
||||
Variant result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
System.out.println("setting quit");
|
||||
script.quit = true;
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.out.println("main done");
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* Here we create the ScriptControl component in a separate MTA thread
|
||||
* and then call the Eval method from the main thread. The main thread
|
||||
* must also be an MTA thread. If you try to create it as an STA
|
||||
* then you will not be able to make calls into a component running
|
||||
* in another thread.
|
||||
*/
|
||||
class ScriptTest3 extends Thread
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static DispatchEvents de = null;
|
||||
public static Dispatch sControl = null;
|
||||
public static boolean quit = false;
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
ComThread.InitMTA();
|
||||
System.out.println("OnInit");
|
||||
String lang = "VBScript";
|
||||
sC = new ActiveXComponent("ScriptControl");
|
||||
sControl = (Dispatch)sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
ScriptTestErrEvents te = new ScriptTestErrEvents();
|
||||
de = new DispatchEvents(sControl, te);
|
||||
System.out.println("sControl="+sControl);
|
||||
while (!quit) sleep(100);
|
||||
ComThread.Release();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.out.println("worker thread exits");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
try {
|
||||
ComThread.InitMTA();
|
||||
ScriptTest3 script = new ScriptTest3();
|
||||
script.start();
|
||||
Thread.sleep(1000);
|
||||
|
||||
Variant result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
System.out.println("setting quit");
|
||||
ScriptTest3.quit = true;
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.out.println("main done");
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
samples/com/jacob/samples/test/ScriptTest3ActiveX.java
Normal file
66
samples/com/jacob/samples/test/ScriptTest3ActiveX.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* Here we create the ScriptControl component in a separate MTA thread
|
||||
* and then call the Eval method from the main thread. The main thread
|
||||
* must also be an MTA thread. If you try to create it as an STA
|
||||
* then you will not be able to make calls into a component running
|
||||
* in another thread.
|
||||
*/
|
||||
class ScriptTest3ActiveX extends Thread
|
||||
{
|
||||
public static ActiveXComponent sC;
|
||||
public static DispatchEvents de = null;
|
||||
public static boolean quit = false;
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
ComThread.InitMTA();
|
||||
System.out.println("OnInit");
|
||||
String lang = "VBScript";
|
||||
sC = new ActiveXComponent("ScriptControl");
|
||||
sC.setProperty("Language", lang);
|
||||
ScriptTestErrEvents te = new ScriptTestErrEvents();
|
||||
de = new DispatchEvents(sC, te);
|
||||
System.out.println("sControl="+sC);
|
||||
while (!quit) sleep(100);
|
||||
ComThread.Release();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.out.println("worker thread exits");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
try {
|
||||
ComThread.InitMTA();
|
||||
ScriptTest3ActiveX script = new ScriptTest3ActiveX();
|
||||
script.start();
|
||||
Thread.sleep(1000);
|
||||
|
||||
Variant result = sC.invoke("Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
System.out.println("setting quit");
|
||||
ScriptTest3ActiveX.quit = true;
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.out.println("main done");
|
||||
ComThread.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
samples/com/jacob/samples/test/ScriptTestActiveX.java
Normal file
46
samples/com/jacob/samples/test/ScriptTestActiveX.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
/**
|
||||
* In this case the component is created and used in the same thread
|
||||
* and it's an Apartment Threaded component, so we call InitSTA.
|
||||
*/
|
||||
class ScriptTestActiveX
|
||||
{
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
ComThread.InitSTA(true);
|
||||
DispatchEvents de = null;
|
||||
|
||||
try {
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
sC.setProperty("Language",lang);
|
||||
ScriptTestErrEvents te = new ScriptTestErrEvents();
|
||||
de = new DispatchEvents(sC, te);
|
||||
Variant result;
|
||||
result = sC.invoke("Eval",args[0]);
|
||||
// call it twice to see the objects reused
|
||||
result = sC.invoke("Eval",args[0]);
|
||||
// call it 3 times to see the objects reused
|
||||
result = sC.invoke("Eval",args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Integer I = null;
|
||||
for(int i=1;i<1000000;i++)
|
||||
{
|
||||
I = new Integer(i);
|
||||
}
|
||||
System.out.println(I);
|
||||
ComThread.Release();
|
||||
ComThread.quitMainSTA();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
samples/com/jacob/samples/test/ScriptTestErrEvents.java
Normal file
19
samples/com/jacob/samples/test/ScriptTestErrEvents.java
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.Variant;
|
||||
|
||||
/**
|
||||
* Extracted from ScriptTest so everyone can see this
|
||||
*/
|
||||
public class ScriptTestErrEvents {
|
||||
|
||||
public void Error(Variant[] args)
|
||||
{
|
||||
System.out.println("java callback for error!");
|
||||
}
|
||||
public void Timeout(Variant[] args)
|
||||
{
|
||||
System.out.println("java callback for error!");
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,67 @@
|
||||
// Face.cpp : Implementation of CMultiFaceApp and DLL registration.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MultiFace.h"
|
||||
#include "Face.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
STDMETHODIMP Face::InterfaceSupportsErrorInfo(REFIID riid)
|
||||
{
|
||||
static const IID* arr[] =
|
||||
{
|
||||
&IID_IFace1,
|
||||
&IID_IFace2,
|
||||
&IID_IFace3,
|
||||
};
|
||||
|
||||
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
|
||||
{
|
||||
if (InlineIsEqualGUID(*arr[i],riid))
|
||||
return S_OK;
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::get_Face1Name(BSTR *pVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
*pVal = name1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::put_Face1Name(BSTR newVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
name1 = newVal;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::get_Face2Nam(BSTR *pVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
*pVal = name2;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::put_Face2Nam(BSTR newVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
name2 = newVal;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::get_Face3Name(BSTR *pVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
*pVal = name3;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::put_Face3Name(BSTR newVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
name3 = newVal;
|
||||
return S_OK;
|
||||
}
|
||||
// Face.cpp : Implementation of CMultiFaceApp and DLL registration.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MultiFace.h"
|
||||
#include "Face.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
STDMETHODIMP Face::InterfaceSupportsErrorInfo(REFIID riid)
|
||||
{
|
||||
static const IID* arr[] =
|
||||
{
|
||||
&IID_IFace1,
|
||||
&IID_IFace2,
|
||||
&IID_IFace3,
|
||||
};
|
||||
|
||||
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
|
||||
{
|
||||
if (InlineIsEqualGUID(*arr[i],riid))
|
||||
return S_OK;
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::get_Face1Name(BSTR *pVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
*pVal = name1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::put_Face1Name(BSTR newVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
name1 = newVal;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::get_Face2Nam(BSTR *pVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
*pVal = name2;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::put_Face2Nam(BSTR newVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
name2 = newVal;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::get_Face3Name(BSTR *pVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
*pVal = name3;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Face::put_Face3Name(BSTR newVal)
|
||||
{
|
||||
// TODO: Add your implementation code here
|
||||
name3 = newVal;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -1,63 +1,63 @@
|
||||
// Face.h: Definition of the Face class
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_FACE_H__9BF24413_B2E0_11D4_A695_00104BFF3241__INCLUDED_)
|
||||
#define AFX_FACE_H__9BF24413_B2E0_11D4_A695_00104BFF3241__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "resource.h" // main symbols
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Face
|
||||
|
||||
class Face :
|
||||
public IDispatchImpl<IFace1, &IID_IFace1, &LIBID_MULTIFACELib>,
|
||||
public IDispatchImpl<IFace2, &IID_IFace2, &LIBID_MULTIFACELib>,
|
||||
public IDispatchImpl<IFace3, &IID_IFace3, &LIBID_MULTIFACELib>,
|
||||
public ISupportErrorInfo,
|
||||
public CComObjectRoot,
|
||||
public CComCoClass<Face,&CLSID_Face>
|
||||
{
|
||||
// IFace1
|
||||
private:
|
||||
CComBSTR name1;
|
||||
|
||||
// IFace2
|
||||
CComBSTR name2;
|
||||
|
||||
// IFace3
|
||||
CComBSTR name3;
|
||||
|
||||
public:
|
||||
Face() {}
|
||||
BEGIN_COM_MAP(Face)
|
||||
COM_INTERFACE_ENTRY2(IDispatch, IFace1)
|
||||
COM_INTERFACE_ENTRY(IFace1)
|
||||
COM_INTERFACE_ENTRY(IFace2)
|
||||
COM_INTERFACE_ENTRY(IFace3)
|
||||
COM_INTERFACE_ENTRY(ISupportErrorInfo)
|
||||
END_COM_MAP()
|
||||
//DECLARE_NOT_AGGREGATABLE(Face)
|
||||
// Remove the comment from the line above if you don't want your object to
|
||||
// support aggregation.
|
||||
|
||||
DECLARE_REGISTRY_RESOURCEID(IDR_Face)
|
||||
// ISupportsErrorInfo
|
||||
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
STDMETHOD(get_Face3Name)(/*[out, retval]*/ BSTR *pVal);
|
||||
STDMETHOD(put_Face3Name)(/*[in]*/ BSTR newVal);
|
||||
STDMETHOD(get_Face2Nam)(/*[out, retval]*/ BSTR *pVal);
|
||||
STDMETHOD(put_Face2Nam)(/*[in]*/ BSTR newVal);
|
||||
STDMETHOD(get_Face1Name)(/*[out, retval]*/ BSTR *pVal);
|
||||
STDMETHOD(put_Face1Name)(/*[in]*/ BSTR newVal);
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_FACE_H__9BF24413_B2E0_11D4_A695_00104BFF3241__INCLUDED_)
|
||||
// Face.h: Definition of the Face class
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_FACE_H__9BF24413_B2E0_11D4_A695_00104BFF3241__INCLUDED_)
|
||||
#define AFX_FACE_H__9BF24413_B2E0_11D4_A695_00104BFF3241__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "resource.h" // main symbols
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Face
|
||||
|
||||
class Face :
|
||||
public IDispatchImpl<IFace1, &IID_IFace1, &LIBID_MULTIFACELib>,
|
||||
public IDispatchImpl<IFace2, &IID_IFace2, &LIBID_MULTIFACELib>,
|
||||
public IDispatchImpl<IFace3, &IID_IFace3, &LIBID_MULTIFACELib>,
|
||||
public ISupportErrorInfo,
|
||||
public CComObjectRoot,
|
||||
public CComCoClass<Face,&CLSID_Face>
|
||||
{
|
||||
// IFace1
|
||||
private:
|
||||
CComBSTR name1;
|
||||
|
||||
// IFace2
|
||||
CComBSTR name2;
|
||||
|
||||
// IFace3
|
||||
CComBSTR name3;
|
||||
|
||||
public:
|
||||
Face() {}
|
||||
BEGIN_COM_MAP(Face)
|
||||
COM_INTERFACE_ENTRY2(IDispatch, IFace1)
|
||||
COM_INTERFACE_ENTRY(IFace1)
|
||||
COM_INTERFACE_ENTRY(IFace2)
|
||||
COM_INTERFACE_ENTRY(IFace3)
|
||||
COM_INTERFACE_ENTRY(ISupportErrorInfo)
|
||||
END_COM_MAP()
|
||||
//DECLARE_NOT_AGGREGATABLE(Face)
|
||||
// Remove the comment from the line above if you don't want your object to
|
||||
// support aggregation.
|
||||
|
||||
DECLARE_REGISTRY_RESOURCEID(IDR_Face)
|
||||
// ISupportsErrorInfo
|
||||
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
STDMETHOD(get_Face3Name)(/*[out, retval]*/ BSTR *pVal);
|
||||
STDMETHOD(put_Face3Name)(/*[in]*/ BSTR newVal);
|
||||
STDMETHOD(get_Face2Nam)(/*[out, retval]*/ BSTR *pVal);
|
||||
STDMETHOD(put_Face2Nam)(/*[in]*/ BSTR newVal);
|
||||
STDMETHOD(get_Face1Name)(/*[out, retval]*/ BSTR *pVal);
|
||||
STDMETHOD(put_Face1Name)(/*[in]*/ BSTR newVal);
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_FACE_H__9BF24413_B2E0_11D4_A695_00104BFF3241__INCLUDED_)
|
||||
@@ -1,72 +1,72 @@
|
||||
// MultiFace.cpp : Implementation of DLL Exports.
|
||||
|
||||
|
||||
// Note: Proxy/Stub Information
|
||||
// To build a separate proxy/stub DLL,
|
||||
// run nmake -f MultiFaceps.mk in the project directory.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "resource.h"
|
||||
#include <initguid.h>
|
||||
#include "MultiFace.h"
|
||||
|
||||
#include "MultiFace_i.c"
|
||||
#include "Face.h"
|
||||
|
||||
|
||||
CComModule _Module;
|
||||
|
||||
BEGIN_OBJECT_MAP(ObjectMap)
|
||||
OBJECT_ENTRY(CLSID_Face, Face)
|
||||
END_OBJECT_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DLL Entry Point
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
_Module.Init(ObjectMap, hInstance, &LIBID_MULTIFACELib);
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
}
|
||||
else if (dwReason == DLL_PROCESS_DETACH)
|
||||
_Module.Term();
|
||||
return TRUE; // ok
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Used to determine whether the DLL can be unloaded by OLE
|
||||
|
||||
STDAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Returns a class factory to create an object of the requested type
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
||||
{
|
||||
return _Module.GetClassObject(rclsid, riid, ppv);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DllRegisterServer - Adds entries to the system registry
|
||||
|
||||
STDAPI DllRegisterServer(void)
|
||||
{
|
||||
// registers object, typelib and all interfaces in typelib
|
||||
return _Module.RegisterServer(TRUE);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DllUnregisterServer - Removes entries from the system registry
|
||||
|
||||
STDAPI DllUnregisterServer(void)
|
||||
{
|
||||
return _Module.UnregisterServer(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// MultiFace.cpp : Implementation of DLL Exports.
|
||||
|
||||
|
||||
// Note: Proxy/Stub Information
|
||||
// To build a separate proxy/stub DLL,
|
||||
// run nmake -f MultiFaceps.mk in the project directory.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "resource.h"
|
||||
#include <initguid.h>
|
||||
#include "MultiFace.h"
|
||||
|
||||
#include "MultiFace_i.c"
|
||||
#include "Face.h"
|
||||
|
||||
|
||||
CComModule _Module;
|
||||
|
||||
BEGIN_OBJECT_MAP(ObjectMap)
|
||||
OBJECT_ENTRY(CLSID_Face, Face)
|
||||
END_OBJECT_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DLL Entry Point
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
_Module.Init(ObjectMap, hInstance, &LIBID_MULTIFACELib);
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
}
|
||||
else if (dwReason == DLL_PROCESS_DETACH)
|
||||
_Module.Term();
|
||||
return TRUE; // ok
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Used to determine whether the DLL can be unloaded by OLE
|
||||
|
||||
STDAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Returns a class factory to create an object of the requested type
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
||||
{
|
||||
return _Module.GetClassObject(rclsid, riid, ppv);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DllRegisterServer - Adds entries to the system registry
|
||||
|
||||
STDAPI DllRegisterServer(void)
|
||||
{
|
||||
// registers object, typelib and all interfaces in typelib
|
||||
return _Module.RegisterServer(TRUE);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DllUnregisterServer - Removes entries from the system registry
|
||||
|
||||
STDAPI DllUnregisterServer(void)
|
||||
{
|
||||
return _Module.UnregisterServer(TRUE);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// stdafx.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef _ATL_STATIC_REGISTRY
|
||||
#include <statreg.h>
|
||||
#include <statreg.cpp>
|
||||
#endif
|
||||
|
||||
#include <atlimpl.cpp>
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// stdafx.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef _ATL_STATIC_REGISTRY
|
||||
#include <statreg.h>
|
||||
#include <statreg.cpp>
|
||||
#endif
|
||||
|
||||
#include <atlimpl.cpp>
|
||||
@@ -1,27 +1,27 @@
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently,
|
||||
// but are changed infrequently
|
||||
|
||||
#if !defined(AFX_STDAFX_H__9BF24406_B2E0_11D4_A695_00104BFF3241__INCLUDED_)
|
||||
#define AFX_STDAFX_H__9BF24406_B2E0_11D4_A695_00104BFF3241__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#define STRICT
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
#define _ATL_APARTMENT_THREADED
|
||||
|
||||
#include <atlbase.h>
|
||||
//You may derive a class from CComModule and use it if you want to override
|
||||
//something, but do not change the name of _Module
|
||||
extern CComModule _Module;
|
||||
#include <atlcom.h>
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__9BF24406_B2E0_11D4_A695_00104BFF3241__INCLUDED)
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently,
|
||||
// but are changed infrequently
|
||||
|
||||
#if !defined(AFX_STDAFX_H__9BF24406_B2E0_11D4_A695_00104BFF3241__INCLUDED_)
|
||||
#define AFX_STDAFX_H__9BF24406_B2E0_11D4_A695_00104BFF3241__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#define STRICT
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
#define _ATL_APARTMENT_THREADED
|
||||
|
||||
#include <atlbase.h>
|
||||
//You may derive a class from CComModule and use it if you want to override
|
||||
//something, but do not change the name of _Module
|
||||
extern CComModule _Module;
|
||||
#include <atlcom.h>
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__9BF24406_B2E0_11D4_A695_00104BFF3241__INCLUDED)
|
||||
@@ -1,18 +1,18 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by MultiFace.rc
|
||||
//
|
||||
#define IDS_PROJNAME 100
|
||||
#define IDS_FACE_DESC 101
|
||||
#define IDR_Face 102
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 201
|
||||
#define _APS_NEXT_COMMAND_VALUE 32768
|
||||
#define _APS_NEXT_CONTROL_VALUE 201
|
||||
#define _APS_NEXT_SYMED_VALUE 103
|
||||
#endif
|
||||
#endif
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by MultiFace.rc
|
||||
//
|
||||
#define IDS_PROJNAME 100
|
||||
#define IDS_FACE_DESC 101
|
||||
#define IDR_Face 102
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 201
|
||||
#define _APS_NEXT_COMMAND_VALUE 32768
|
||||
#define _APS_NEXT_CONTROL_VALUE 201
|
||||
#define _APS_NEXT_SYMED_VALUE 103
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
package samples.test.atl;
|
||||
package com.jacob.samples.test.atl;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
@@ -1,14 +1,14 @@
|
||||
This example demonstrates how to access multiple interfaces.
|
||||
|
||||
To run it, chdir to MultiFace\Debug and run:
|
||||
regsvr32 MultiFace.dll
|
||||
|
||||
Then, run (in this dir):
|
||||
java MultiFace
|
||||
|
||||
As you can see from MultiFace\MultiFace.idl - there are 3 interfaces.
|
||||
|
||||
By default JACOB attaches to the default interface.
|
||||
|
||||
The file MultiFace.java shows how to use the new Dispatch.QueryInterface
|
||||
to get access to the other interfaces.
|
||||
This example demonstrates how to access multiple interfaces.
|
||||
|
||||
To run it, chdir to MultiFace\Debug and run:
|
||||
regsvr32 MultiFace.dll
|
||||
|
||||
Then, run (in this dir):
|
||||
java MultiFace
|
||||
|
||||
As you can see from MultiFace\MultiFace.idl - there are 3 interfaces.
|
||||
|
||||
By default JACOB attaches to the default interface.
|
||||
|
||||
The file MultiFace.java shows how to use the new Dispatch.QueryInterface
|
||||
to get access to the other interfaces.
|
||||
@@ -1,38 +1,38 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
/*
|
||||
* This example uses the MathTest sample VB COM DLL under
|
||||
* the MathProj directory
|
||||
*/
|
||||
class math
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
Dispatch test = new Dispatch("MathTest.Math");
|
||||
testEvents te = new testEvents();
|
||||
DispatchEvents de = new DispatchEvents(test, te);
|
||||
System.out.println(Dispatch.call(test, "Add", new Variant(1), new Variant(2)));
|
||||
System.out.println(Dispatch.call(test, "Mult", new Variant(2), new Variant(2)));
|
||||
Variant v = Dispatch.call(test, "Mult", new Variant(2), new Variant(2));
|
||||
// this should return false
|
||||
System.out.println("v.isNull="+v.isNull());
|
||||
v = Dispatch.call(test, "getNothing");
|
||||
// these should return nothing
|
||||
System.out.println("v.isNull="+v.isNull());
|
||||
System.out.println("v.toDispatch="+v.toDispatch());
|
||||
}
|
||||
}
|
||||
|
||||
class testEvents {
|
||||
public void DoneAdd(Variant[] args)
|
||||
{
|
||||
System.out.println("DoneAdd called in java");
|
||||
}
|
||||
public void DoneMult(Variant[] args)
|
||||
{
|
||||
System.out.println("DoneMult called in java");
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
/*
|
||||
* This example uses the MathTest sample VB COM DLL under
|
||||
* the MathProj directory
|
||||
*/
|
||||
class math
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
Dispatch test = new Dispatch("MathTest.Math");
|
||||
testEvents te = new testEvents();
|
||||
DispatchEvents de = new DispatchEvents(test, te);
|
||||
System.out.println(Dispatch.call(test, "Add", new Variant(1), new Variant(2)));
|
||||
System.out.println(Dispatch.call(test, "Mult", new Variant(2), new Variant(2)));
|
||||
Variant v = Dispatch.call(test, "Mult", new Variant(2), new Variant(2));
|
||||
// this should return false
|
||||
System.out.println("v.isNull="+v.isNull());
|
||||
v = Dispatch.call(test, "getNothing");
|
||||
// these should return nothing
|
||||
System.out.println("v.isNull="+v.isNull());
|
||||
System.out.println("v.toDispatch="+v.toDispatch());
|
||||
}
|
||||
}
|
||||
|
||||
class testEvents {
|
||||
public void DoneAdd(Variant[] args)
|
||||
{
|
||||
System.out.println("DoneAdd called in java");
|
||||
}
|
||||
public void DoneMult(Variant[] args)
|
||||
{
|
||||
System.out.println("DoneMult called in java");
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,41 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class sa_dispatch
|
||||
{
|
||||
public static void main(String args[])
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
|
||||
try {
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
Dispatch sControl = (Dispatch)sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
|
||||
Variant result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
|
||||
// wrap the script control in a variant
|
||||
Variant v = new Variant(sControl);
|
||||
|
||||
// create a safe array of type dispatch
|
||||
SafeArray sa = new SafeArray(Variant.VariantDispatch, 1);
|
||||
|
||||
// put the variant in the array
|
||||
sa.setVariant(0, v);
|
||||
|
||||
// take it back out
|
||||
Variant v2 = sa.getVariant(0);
|
||||
Dispatch d = v2.toDispatch();
|
||||
|
||||
// make sure you can call eval on it
|
||||
result = Dispatch.call(d, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class sa_dispatch
|
||||
{
|
||||
public static void main(String args[])
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
|
||||
try {
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
Dispatch sControl = (Dispatch)sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
|
||||
Variant result = Dispatch.call(sControl, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
|
||||
// wrap the script control in a variant
|
||||
Variant v = new Variant(sControl);
|
||||
|
||||
// create a safe array of type dispatch
|
||||
SafeArray sa = new SafeArray(Variant.VariantDispatch, 1);
|
||||
|
||||
// put the variant in the array
|
||||
sa.setVariant(0, v);
|
||||
|
||||
// take it back out
|
||||
Variant v2 = sa.getVariant(0);
|
||||
Dispatch d = v2.toDispatch();
|
||||
|
||||
// make sure you can call eval on it
|
||||
result = Dispatch.call(d, "Eval", args[0]);
|
||||
System.out.println("eval("+args[0]+") = "+ result);
|
||||
} catch (ComException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,58 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
class sa_test
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
SafeArray sa = new SafeArray(Variant.VariantVariant, 3);
|
||||
|
||||
sa.fromShortArray(new short[] {1,2,3});
|
||||
System.out.println("sa short="+sa);
|
||||
int[] ai = sa.toIntArray();
|
||||
for(int i=0;i<ai.length;i++) {
|
||||
System.out.println("toInt="+ai[i]);
|
||||
}
|
||||
double[] ad = sa.toDoubleArray();
|
||||
for(int i=0;i<ad.length;i++) {
|
||||
System.out.println("toDouble="+ad[i]);
|
||||
}
|
||||
sa.fromIntArray(new int[] {100000,200000,300000});
|
||||
System.out.println("sa int="+sa);
|
||||
ai = sa.toIntArray();
|
||||
for(int i=0;i<ai.length;i++) {
|
||||
System.out.println("toInt="+ai[i]);
|
||||
}
|
||||
ad = sa.toDoubleArray();
|
||||
for(int i=0;i<ad.length;i++) {
|
||||
System.out.println("toDouble="+ad[i]);
|
||||
}
|
||||
Variant av[] = sa.toVariantArray();
|
||||
for(int i=0;i<av.length;i++) {
|
||||
System.out.println("toVariant="+av[i]);
|
||||
}
|
||||
sa.fromDoubleArray(new double[] {1.5,2.5,3.5});
|
||||
System.out.println("sa double="+sa);
|
||||
sa.fromFloatArray(new float[] {1.5F,2.5F,3.5F});
|
||||
System.out.println("sa float="+sa);
|
||||
sa.fromBooleanArray(new boolean[] {true, false, true, false});
|
||||
System.out.println("sa bool="+sa);
|
||||
av = sa.toVariantArray();
|
||||
for(int i=0;i<av.length;i++) {
|
||||
System.out.println("toVariant="+av[i]);
|
||||
}
|
||||
sa.fromCharArray(new char[] {'a','b','c','d'});
|
||||
System.out.println("sa char="+sa);
|
||||
sa.fromStringArray(new String[] {"hello", "from", "java", "com"});
|
||||
System.out.println("sa string="+sa);
|
||||
av = sa.toVariantArray();
|
||||
for(int i=0;i<av.length;i++) {
|
||||
System.out.println("toVariant="+av[i]);
|
||||
}
|
||||
sa.fromVariantArray(new Variant[] {
|
||||
new Variant(1), new Variant(2.3), new Variant("hi")});
|
||||
System.out.println("sa variant="+sa);
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
|
||||
class sa_test
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
SafeArray sa = new SafeArray(Variant.VariantVariant, 3);
|
||||
|
||||
sa.fromShortArray(new short[] {1,2,3});
|
||||
System.out.println("sa short="+sa);
|
||||
int[] ai = sa.toIntArray();
|
||||
for(int i=0;i<ai.length;i++) {
|
||||
System.out.println("toInt="+ai[i]);
|
||||
}
|
||||
double[] ad = sa.toDoubleArray();
|
||||
for(int i=0;i<ad.length;i++) {
|
||||
System.out.println("toDouble="+ad[i]);
|
||||
}
|
||||
sa.fromIntArray(new int[] {100000,200000,300000});
|
||||
System.out.println("sa int="+sa);
|
||||
ai = sa.toIntArray();
|
||||
for(int i=0;i<ai.length;i++) {
|
||||
System.out.println("toInt="+ai[i]);
|
||||
}
|
||||
ad = sa.toDoubleArray();
|
||||
for(int i=0;i<ad.length;i++) {
|
||||
System.out.println("toDouble="+ad[i]);
|
||||
}
|
||||
Variant av[] = sa.toVariantArray();
|
||||
for(int i=0;i<av.length;i++) {
|
||||
System.out.println("toVariant="+av[i]);
|
||||
}
|
||||
sa.fromDoubleArray(new double[] {1.5,2.5,3.5});
|
||||
System.out.println("sa double="+sa);
|
||||
sa.fromFloatArray(new float[] {1.5F,2.5F,3.5F});
|
||||
System.out.println("sa float="+sa);
|
||||
sa.fromBooleanArray(new boolean[] {true, false, true, false});
|
||||
System.out.println("sa bool="+sa);
|
||||
av = sa.toVariantArray();
|
||||
for(int i=0;i<av.length;i++) {
|
||||
System.out.println("toVariant="+av[i]);
|
||||
}
|
||||
sa.fromCharArray(new char[] {'a','b','c','d'});
|
||||
System.out.println("sa char="+sa);
|
||||
sa.fromStringArray(new String[] {"hello", "from", "java", "com"});
|
||||
System.out.println("sa string="+sa);
|
||||
av = sa.toVariantArray();
|
||||
for(int i=0;i<av.length;i++) {
|
||||
System.out.println("toVariant="+av[i]);
|
||||
}
|
||||
sa.fromVariantArray(new Variant[] {
|
||||
new Variant(1), new Variant(2.3), new Variant("hi")});
|
||||
System.out.println("sa variant="+sa);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,61 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
public class safearray
|
||||
{
|
||||
public static void main(java.lang.String[] args)
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
|
||||
ActiveXComponent xl = new ActiveXComponent("Excel.Application");
|
||||
try {
|
||||
Object cell;
|
||||
Object cellstart;
|
||||
Object cellstop;
|
||||
SafeArray sAProdText;
|
||||
Object workbooks = xl.getProperty("Workbooks").toDispatch();
|
||||
System.out.println("have workbooks");
|
||||
Object workbook = Dispatch.call(workbooks, "Open", "d:\\jacob_15\\samples\\test\\jacobtest.xls").toDispatch();
|
||||
System.out.println("Opened File - jacobtest.xls\n");
|
||||
Object sheet = Dispatch.get(workbook,"ActiveSheet").toDispatch();
|
||||
cell = Dispatch.invoke(sheet,"Range",Dispatch.Get,new Object[] {"A1:D1000"},new int[1]).toDispatch();
|
||||
System.out.println("have cell:"+cell);
|
||||
sAProdText = Dispatch.get(cell,"Value").toSafeArray();
|
||||
System.out.println("sa: dim="+sAProdText.getNumDim());
|
||||
System.out.println("sa: start row="+sAProdText.getLBound(1));
|
||||
System.out.println("sa: start col="+sAProdText.getLBound(2));
|
||||
System.out.println("sa: end row="+sAProdText.getUBound(1));
|
||||
System.out.println("sa: end col="+sAProdText.getUBound(2));
|
||||
int i;
|
||||
int lineNumber=1;
|
||||
boolean stringFound = true;
|
||||
int n = 0;
|
||||
for(lineNumber=1; lineNumber < 1000; lineNumber++)
|
||||
{
|
||||
for (i = 1 ; i < 4 ; i++ ) {
|
||||
System.out.println((n++) + " " + lineNumber+" "+i+" " +sAProdText.getString(lineNumber,i));
|
||||
/*
|
||||
if (sAProdText.getString(lineNumber,i).compareTo("aaaa") != 0 ) {
|
||||
System.out.println("Invalid String in line " + lineNumber + " Cell " + i + " Value = " + sAProdText.getString(lineNumber,i));
|
||||
stringFound = false;
|
||||
}
|
||||
}
|
||||
if (stringFound) {
|
||||
System.out.println("Valid Strings in line " + lineNumber);
|
||||
lineNumber++;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
Dispatch.call(workbook, "Close");
|
||||
System.out.println("Closed File\n");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
xl.invoke("Quit", new Variant[] {});
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
public class safearray
|
||||
{
|
||||
public static void main(java.lang.String[] args)
|
||||
{
|
||||
System.runFinalizersOnExit(true);
|
||||
|
||||
ActiveXComponent xl = new ActiveXComponent("Excel.Application");
|
||||
try {
|
||||
Dispatch cell;
|
||||
Dispatch cellstart;
|
||||
Dispatch cellstop;
|
||||
SafeArray sAProdText;
|
||||
Dispatch workbooks = xl.getProperty("Workbooks").toDispatch();
|
||||
System.out.println("have workbooks");
|
||||
Dispatch workbook = Dispatch.call(workbooks, "Open", "d:\\jacob_15\\samples\\test\\jacobtest.xls").toDispatch();
|
||||
System.out.println("Opened File - jacobtest.xls\n");
|
||||
Dispatch sheet = Dispatch.get(workbook,"ActiveSheet").toDispatch();
|
||||
cell = Dispatch.invoke(sheet,"Range",Dispatch.Get,new Object[] {"A1:D1000"},new int[1]).toDispatch();
|
||||
System.out.println("have cell:"+cell);
|
||||
sAProdText = Dispatch.get(cell,"Value").toSafeArray();
|
||||
System.out.println("sa: dim="+sAProdText.getNumDim());
|
||||
System.out.println("sa: start row="+sAProdText.getLBound(1));
|
||||
System.out.println("sa: start col="+sAProdText.getLBound(2));
|
||||
System.out.println("sa: end row="+sAProdText.getUBound(1));
|
||||
System.out.println("sa: end col="+sAProdText.getUBound(2));
|
||||
int i;
|
||||
int lineNumber=1;
|
||||
boolean stringFound = true;
|
||||
int n = 0;
|
||||
for(lineNumber=1; lineNumber < 1000; lineNumber++)
|
||||
{
|
||||
for (i = 1 ; i < 4 ; i++ ) {
|
||||
System.out.println((n++) + " " + lineNumber+" "+i+" " +sAProdText.getString(lineNumber,i));
|
||||
/*
|
||||
if (sAProdText.getString(lineNumber,i).compareTo("aaaa") != 0 ) {
|
||||
System.out.println("Invalid String in line " + lineNumber + " Cell " + i + " Value = " + sAProdText.getString(lineNumber,i));
|
||||
stringFound = false;
|
||||
}
|
||||
}
|
||||
if (stringFound) {
|
||||
System.out.println("Valid Strings in line " + lineNumber);
|
||||
lineNumber++;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
Dispatch.call(workbook, "Close");
|
||||
System.out.println("Closed File\n");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
xl.invoke("Quit", new Variant[] {});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
package samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class speed
|
||||
{
|
||||
public static void main(String args[])
|
||||
{
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
Object sControl = sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
for(int i=0;i<10000;i++) {
|
||||
Dispatch.call(sControl, "Eval", "1+1");
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.jacob.samples.test;
|
||||
|
||||
import com.jacob.com.*;
|
||||
import com.jacob.activeX.*;
|
||||
|
||||
class speed
|
||||
{
|
||||
public static void main(String args[])
|
||||
{
|
||||
String lang = "VBScript";
|
||||
ActiveXComponent sC = new ActiveXComponent("ScriptControl");
|
||||
Dispatch sControl = sC.getObject();
|
||||
Dispatch.put(sControl, "Language", lang);
|
||||
for(int i=0;i<10000;i++) {
|
||||
Dispatch.call(sControl, "Eval", "1+1");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user