blob: 462a42ee54e7e7e2d532c3eb70b4977df2813f4b [file] [log] [blame]
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Grant Gayed">
<link href="../article.css" type="text/css" rel="stylesheet">
<title>ActiveX Support In SWT</title>
<h1>ActiveX Support In SWT</h1>
<div class="summary">
<p>OLE Documents, such as Word, Excel or PowerPoint, and ActiveX
Controls such as Internet Explorer are COM objects that can be embedded
into other applications running on a Microsoft&reg; Windows&reg;
platform. This article provides an overview of integrating OLE Documents
and ActiveX Controls into an application using SWT.</p>
<div class="author">By Veronika Irvine, OTI</div>
<div class="copyright">Copyright &copy; 2001 Object Technology
International, Inc.</div>
<div class="date">March 22, 2001</div>
<div class="content">
<h2>Embedding an OLE Object in your SWT Application</h2>
<p>OLE Objects can be contained in SWT widgets. From there, they can
be activated and deactivated for user interaction, and manipulated by
the application according to their specification. For example, edited
data and state can be retrieved or saved. If the object is no longer
required, it can be disposed.</p>
<h3>Create the OLE Object</h3>
<p>An OLE Document or ActiveX Control is added to an application by
inserting it into a Container. The Container is made up of two parts:</p>
<li>The <i> OleFrame</i> object handles sizing, menu management
and window placement.</li>
<li>The <i> OleClientSite</i> (for OLE Documents) or <i>
OleControlSite</i> (for ActiveX Controls) handles interactions with a
specific OLE Object.</li>
<p>The first step in embedding an OLE Object is to create the <i>OleFrame</i>:</p>
Display display = new Display();
Shell shell = new Shell(display);
OleFrame frame = new OleFrame(shell, SWT.NONE);
<p>When activated, an OLE Document displays its own menu bar over
top of the application's menu bar. The application can contribute menus
to the OLE Document's menu bar through the <i> OleFrame</i> as follows:</p>
Menu bar = new Menu(shell, SWT.BAR);
MenuItem fileItem1 = new MenuItem(bar, SWT.CASCADE);
MenuItem fileItem2 = new MenuItem(bar, SWT.CASCADE);
MenuItem containerItem = new MenuItem(bar, SWT.CASCADE);
MenuItem windowItem1 = new MenuItem(bar, SWT.CASCADE);
MenuItem windowItem2 = new MenuItem(bar, SWT.CASCADE);
frame.setFileMenus(new MenuItem[] {fileItem1, fileItem2});
frame.setContainerMenus(new MenuItem[] {containerItem});
frame.setWindowMenus(new MenuItem[] {windowItem1, windowItem2});
<p>The next step is to create an <i> OleClientSite</i> or an <i>OleControlSite</i>.
Some COM objects can function as both an OLE Document and an ActiveX
Control. Embedding an OLE Document is equivalent to embedding the entire
application. The OLE Document provides its own toolbar and menu bar for
accessing its behavior. An ActiveX Control only provides the content
part and the parent application must manage the behavior of the content
through the API of the ActiveX Control. To determine if a COM object
supports the OLE Document behavior, look for the IOleDocument interface.
To determine if a COM object supports the ActiveX Control behavior, look
for the IOleControl interface. To see which interfaces the OLE Object
implements, look at the type library.</p>
<p>To embed an OLE Document, create an <i> OleClientSite</i> object.
To embed an ActiveX Control, create an <i> OleControlSite</i> object.
The parent in either case is the <i>OleFrame</i>. When you create the <i>
OleClientSite</i> or the <i>OleControlSite</i>, the associated OLE Document
or ActiveX Control will automatically be created and associated with the
container site.</p>
<p>There are two ways to create an <i>OleClientSite</i>:</p>
<li>Create an <i> OleClientSite</i> from a ProgramID. A ProgramID
is a string that identifies the application. For example, the ProgramID
for Word is &quot;Word.Document&quot; and the ProgramID for Excel is
&quot;Excel.Chart&quot;. The ProgramID for an application can be found
in the Windows Registry. Using the following constructor, a blank
document is created (similar to choosing File->New from a standalone
OleClientSite clientSite = new OleClientSite(frame, SWT.NONE, &quot;Word.Document&quot;);
<li>Create an <i> OleClientSite</i> from a Storage file. A Storage
file is a file with an OLE format that contains information about the
type of OLE Object that can view it. It also contains a structured
storage format and will store information such as paragraph formats,
dictionaries or Author/Title/Description tags. For example, a
&quot;.doc&quot; file created by Word is a Storage file. Given a
Storage file, OLE will figure out which OLE Document to create.</li>
File file = new File(&quot;C:\\OleDocumentation.doc&quot;);
OleClientSite clientSite = new OleClientSite(frame, SWT.NONE, file);
<p>An <i> OleControlSite</i> is created from the ProgramID for the
ActiveX Control. For example, the ProgramID for the Internet Explorer is
&quot;Shell.Explorer&quot;. The web browser can be embedded in an
application as follows:</p>
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
<h3>Activate the OLE Object</h3>
<p>The final step before an OLE Document or ActiveX control becomes
visible inside the application is to activate the OLE Object (often
referred to as <i> in-place activation</i>). This is done by invoking
the &quot;doVerb&quot; action on the <i> OleClientSite</i> or <i>
OleControlSite</i>. The &quot;doVerb&quot; syntax is as follows:</p>
public int doVerb(int verb)
<li><b>verb</b> &ndash; an integer value mapping to one of the
following pre-defined verb values:</li>
<li>OLE.OLEIVERB_PRIMARY &ndash; Specifies the action that occurs
when an end user double-clicks the object in its container. The
object, not the container, determines this action. If the object
supports in-place activation, the primary verb usually activates the
object in place.</li>
<li>OLE.OLEIVERB_SHOW &ndash; Instructs an object to show itself
for editing or viewing. Called to display newly inserted objects for
initial editing and to show link sources. Usually an alias for some
other object-defined verb.</li>
<li>OLE.OLEIVERB_OPEN &ndash; Instructs an object, including one
that otherwise supports in-place activation, to open itself for
editing in a window separate from that of its container. If the object
does not support in-place activation, this verb has the same semantics
<li>OLE.OLEIVERB_HIDE &ndash; Causes an object to remove its user
interface from the view. Applies only to objects that are activated
<li>OLE.OLEIVERB_INPLACEACTIVATE &ndash; Activates an object in
place without displaying tools, such as menus and toolbars, that end
users need to change the behavior or appearance of the object.
Single-clicking such an object causes it to negotiate the display of
its user-interface tools with its container. If the container refuses,
the object remains active but without its tools displayed.</li>
<li>OLE.OLEIVERB_UIACTIVATE &ndash; Activates an object in place,
along with its full set of user-interface tools, including menus,
toolbars, and its name in the title bar of the container window.</li>
<li>OLE.OLEIVERB_DISCARDUNDOSTATE &ndash; Used to tell objects to
discard any undo state that they may be maintaining without
deactivating the object.</li>
<li><b>return value</b> &ndash; OLE.S_OK if the doVerb command was
<p><b>Further Reading</b> on &quot;doVerb&quot;: MSDN Library:
Windows CE Documentation-&gt;Application Development-&gt;API
<h3>Saving changes to an OLE Document</h3>
<p>The changes made to the OLE Document can be saved to a Storage
file or an ordinary file. As described above, a Storage file contains
information in the header that is specific to OLE.</p>
<p>Applications like Word save additional information in the Storage
file such as paragraph formats, Author's name and Company. If you save a
Word Document to an ordinary file, only the text will be saved.</p>
<p>Some applications edit resources which are not OLE specific and
therefore can not save their contents into a Storage file because then
other applications will not understand the contents. For example, a
bitmap can be edited with Microsoft's Paint application which can be
embedded as an OLE Document. A bitmap, however, has a format that does
not include an OLE header. In this case, the contents must be saved to
an ordinary file.</p>
<p>Before saving the file, check that a save is necessary using the
method <tt>isDirty()</tt> on the <i>OleClientSite</i>. If a save is
required, invoke the method <tt>save(File file, boolean
includeOleInfo)</tt> on the <i>OleClientSite</i>. The boolean <tt>includeOleInfo</tt>
should be set to <b> true</b> to save to a Storage file and <b>false</b> to save to an ordinary file.</p>
File file = new File(&quot;C:\\OleDocumentation.doc&quot;);
OleClientSite clientSite = new OleClientSite(frame, SWT.NONE, file);
// ... edit the document ...
if (clientSite.isDirty()) {
File tempFile = new File(file.getAbsolutePath() + &quot;.tmp&quot;);
if (, true)){
// save was successful so discard the backup
} else {
// save failed so restore the backup
<h3>Deactivating the OLE Object</h3>
<p>If several OLE Documents or ActiveX Controls are embedded in an
application, it may be preferable to have only one OLE Object "active"
at a time. The OLE Object that is not currently being used can be
deactivated. When the OLE Object is deactivated, it is placed in a
&quot;Running&quot; state, its contents are visible but the toolbar and
menu bar have been removed and the content does not respond to mouse or
keyboard actions. In this state, the object is still alive. If
modifications have been made to the object, when the object is returned
to the active state, those changes will still be present.</p>
<p>NOTE: In the case of OLE Documents, the order of activating and
deactivating is very important; first deactivate the old document and
then activate the new document otherwise the menu bar will not appear
<p>Deactivating an OLE Document or ActiveX Control is done by
calling <tt>deactivateInPlaceClient</tt> on the <i> OleClientSite</i> or
<h3>Disposing the OLE Object</h3>
<p>Because <i> OleFrame</i>, <i> OleClientSite</i> and <i>
OleControlSite</i> are SWT Widgets, when the parent is disposed, the
children will be disposed automatically. To terminate an OLE Document or
ActiveX Control while other OLE Objects are still running in the same <i>
OleFrame</i>, directly dispose of the object:</p>
<p>Note: When an OLE Object is terminated, saving is not performed
automatically, nor will there be any checking for a &quot;dirty&quot;
state (no checking for unsaved changes before closing). The application
must write this code.</p>
<h2>Using Customized Behavior</h2>
<p>ActiveX Controls and OLE Documents can provide customized behavior. To
see what kinds of customized behavior are available refer to the type
library associated with the OLE Object. SWT provides access to several
different types of customized behavior: the &quot;Exec Command&quot;,
the &quot;IDispatch interface&quot;, Events and Property Change
<h3>Exec Command</h3>
<p>The &quot;exec&quot; command is a generic way of sending a predefined
set of commands to either an OLE Document or an ActiveX Control. The
command syntax is as follows:</p>
int OleClientSite.exec(int cmdID, int options, Variant in, Variant out)
<li><b>cmdID</b> &ndash; an identifier for the command such as
<li><b>options</b> &ndash; the behavior of the command can be
modified through the use of options such as
<li><b>in</b> &ndash; parameters to be passed into the command</li>
<li><b>out</b> &ndash; values return from the command</li>
<li><b>return value</b> &ndash; the return value will be OLE.S_OK
if the action was successful.</li>
<p>In and out parameters are defined using a Variant, which is the
OLE mechanism for generically passing around any type of data. A Variant
may contain an integer, a boolean, a string or many other different
types of objects.</p>
<p>The OLE Object may or may not recognize the command. Before
sending a command, you can ask an OLE Object if it recognizes the
command using OleClientSite.queryStatus(int cmdID). This will return
some combination of the following values:</p>
<li>OLE.OLECMDF_SUPPORTED &ndash; The command is supported by this
<li>OLE.OLECMDF_ENABLED &ndash; The command is available and
<li>OLE.OLECMDF_LATCHED &ndash; The command is an on-off toggle
and is currently on.</li>
<p>Here is an example of how the Exec command is used:</p>
int result = controlSite.queryStatus(OLE.OLECMDID_PRINT);
<p><b>Further Reading</b> on &quot;exec&quot;: MSDN Library:
Platform SDK->Component Services ->COM ->OLE and Data
Transfer->Reference ->Interfaces->IOleCommandTarget</p>
<h3>IDispatch or OLE Automation</h3>
<p>An OLE Document or ActiveX Control can also provide a much richer set of
commands than the generic set defined for the &quot;exec&quot; command.
To access these, use the IDispatch interface. IDispatch provides access
to get and set property values and invoke methods. For example, Word
provides the entire Word Basic interface that gives you access to all
sorts of commands and properties like cut/copy/paste, print, spell
check, select text, change paragraph format, etc. In SWT the IDispatch
capabilities are accessed using the <i> OleAutomation</i> object.</p>
<h4>Creating the Automation object:</h4>
<p>An <i> OleAutomation</i> object can be created from a client or control
site or it can be obtained as the return value from a method invocation.</p>
<p>A simple case is the Web Browser. It provides commands like
navigate, back, forward, home which you can access like this:</p>
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
OleAutomation automation = new OleAutomation(controlSite );
<h4>Get a Property</h4>
<p>A Property is obtained from an OLE Object using the <i>
OleAutomation</i> method <tt><b>getProperty</b></tt>:</p>
Variant getProperty(int dispIdMember)
<li><b>dispIDMember</b> - identifies the Property in which you are
interested. You may already know the value of the dispIDMember from
looking in the type library or you may just know the string identifier
(also available in the type library). You can get the integer value
from the string identifier using <tt>OleAutomation.GetIDsOfNames(String[]
names)</tt>. The method getProperty returns a Variant; as discussed above,
this is the OLE mechanism for being able to generically pass around any
type of data. You ask the Variant to provide the value it contains in
the format that you require.</li>
<li><b>return value</b> - this is a Variant containing the value
of the property. A Variant is a generic way of passing around data. You
can ask the Variant for the data in the format that you prefer.</li>
<p>For example:</p>
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
OleAutomation automation = new OleAutomation(controlSite);
int[] rgdispid = automation.getIDsOfNames(new String[]{&quot;LocationName&quot;});
int dispIdMember = rgdispid[0];
Variant result = automation.getProperty(dispIdMember);
System.out.println(&quot;The Web Browser is currently viewing the URL &quot;+result.getString());
<p>Matching type library record:</p>
interface IWebBrowser : IDispatch {
[id(0x000000d2), propget, helpstring(&quot;Gets the short (UI-friendly) name of the URL/file currently viewed.&quot;)]
HRESULT LocationName([out, retval] BSTR* LocationName);
<h4>Set a Property</h4>
<p>This is very similar to &quot;Get a Property&quot;. In this case the
method is:</p>
boolean OleAutomation.setProperty(int dispIdMember, Variant rgvarg).
<li><b>dispIdMember</b> &ndash; as above</li>
<li><b>rgvarg</b> - contains the value to which you want the
property set.</li>
<li><b>return value</b> &ndash; true if property was set.</li>
<p>For example:</p>
// Allow multiple selection in an embedded Calendar Control
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;MSComCtl2.MonthView&quot;);
OleAutomation automation = new OleAutomation(controlSite);
int[] rgdispid = automation.getIDsOfNames(new String[]{&quot;MultiSelect&quot;});
int dispIdMember = rgdispid[0];
Variant multiSelect = new Variant((short)1); // set to true (0 = false)
automation.setProperty(dispIdMember, multiSelect);
<p>Matching type library record:</p>
interface IMonthView : IDispatch {
[id(0x000000013), propput, helpstring(&quot;Allow multiple selection.&quot;), helpcontext(0x00030da8)]
HRESULT MultiSelect([in] BSTR pbMultiSelect);
<h4>Invoke a Command</h4>
<p>Invoking a command is a bit more complicated because you can pass
in multiple parameters and because some of these parameters may be
optional, you must pass an identifier for the parameter as well as the
value of the parameter. There are three variants on the
OleAutomation.invoke method to accommodate this:</p>
<li><tt>Variant invoke(int dispIdMember)</tt> &ndash; Command
takes no parameters</li>
<li><tt>Variant invoke(int dispIdMember, Variant[] rgvarg)</tt>
&ndash; All parameters are mandatory and therefore none are named</li>
<li><tt>Variant invoke(int dispIdMember, Variant[] rgvarg,
int[] rgdispidNamedArgs)</tt> &ndash; Some parameters are optional and
therefore all the parameters are named</li>
<li><b>dispIdMember</b> &ndash; the identifier of the command</li>
<li><b>rgvarg</b> &ndash; an array of Variants holding the values
of the parameters you are passing in.</li>
<li><b>rgdispidNamedArgs</b> &ndash; an array of the identifiers
for the arguments.</li>
<li><b>return value</b> &ndash; a Variant containing the result
that was passed back by the command. Depending on the command, this may
be null.</li>
<p>Example 1:</p>
<p>The &quot;GoForward&quot; command on the Web Browser takes no
OleControlSite webSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
OleAutomation automation = new OleAutomation(webSite);
int[] rgdispid = automation.getIDsOfNames(new String[]{&quot;GoForward&quot;});
int dispIdMember = rgdispid[0];
Variant pVarResult = automation.invoke(dispIdMember);
</pre> Note: Call <b> getIDsOfNames</b> to get the ID of the command
<p>Matching type library record:</p>
interface IWebBrowser : IDispatch {
[id(0x00000065), helpstring(&quot;Navigates to the next item in the history list.&quot;)]
HRESULT GoForward();
<p>Example 2:</p>
<p>The &quot;Navigate&quot; command of the Web Browser takes several
arguments but there is only one mandatory parameter and that is the
&quot;URL&quot;. In this example we are not going to send any of the
optional arguments:</p>
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
OleAutomation automation = new OleAutomation(controlSite);
int[] rgdispid = automation.getIDsOfNames(new String[]{&quot;Navigate&quot;});
int dispIdMember = rgdispid[0];
Variant[] rgvarg = new Variant[1]; // this is the URL parameter
rgvarg[0] = new Variant(&quot;;);
Variant pVarResult = automation.invoke(dispIdMember, rgvarg);
<p>Matching type library record:</p>
interface IWebBrowser : IDispatch {
[id(0x00000068), helpstring(&quot;Navigates to a URL or file.&quot;)]
HRESULT Navigate(
[in] BSTR URL,&nbsp;
[in, optional] VARIANT* Flags,
[in, optional] VARIANT* TargetFrameName,&nbsp;
[in, optional] VARIANT* PostData,&nbsp;
[in, optional] VARIANT* Headers);
<p>Example 3:</p>
<p>The &quot;FormatFont&quot; command in Word Basic takes several
optional parameters and we are interested in just a few of them:</p>
// This is a helper method for getting access to Word's WordBasic IDispatch interface
// because it is rather complicated
private OleAutomation getWordBasic(OleClientSite clientSite) {
// Get generic IDispatch interface
OleAutomation dispInterface = new OleAutomation(clientSite);
// Get Application
int[] appId = dispInterface.getIDsOfNames(new String[]{&quot;Application&quot;});
if (appId == null) OLE.error(OLE.ERROR_APPLICATION_NOT_FOUND);
Variant pVarResult = dispInterface.getProperty(appId[0]);
if (pVarResult == null) OLE.error(OLE.ERROR_APPLICATION_NOT_FOUND);
OleAutomation application = pVarResult.getAutomation();
// Get Word Basic
int[] wbId = application.getIDsOfNames(new String[]{&quot;WordBasic&quot;});
Variant pVarResult2 = application.getProperty(wbId[0]);
if (pVarResult2 == null) OLE.error(OLE.ERROR_APPLICATION_NOT_FOUND);
return pVarResult2.getAutomation();
OleClientSite clientSite = new OleClientSite(frame, SWT.NONE, &quot;Word.Document&quot;);
OleAutomation automation = getWordBasic(clientSite);
// set the font to 12 point, Italic, Bold - ignore Color and Font name
int[] rgdispid = automation.getIDsOfNames(new String[]{&quot;FormatFont&quot;, &quot;Points&quot;, &quot;Color&quot;, &quot;Font&quot;, &quot;Bold&quot;, &quot;Italic&quot;});
int dispIdMember = rgdispid[0];
Variant[] rgvarg = new Variant[3];
int[] rgdispidNamedArgs = new int[3];
rgvarg[0] = new Variant(12); // this is the Points parameter
rgdispidNamedArgs[0] = rgdispid[1];
rgvarg[1] = new Variant(1); // this is the Bold parameter
rgdispidNamedArgs[1] = rgdispid[4];
rgvarg[2] = new Variant(1); // this is the Italic
rgdispidNamedArgs[2] = rgdispid[5];
automation.invokeNoReply(dispIdMember, rgvarg, rgdispidNamedArgs);
<p>Note: Here we have used <b>invokeNoReply</b> instead of <b>invoke</b>.
Word was the first OLE Document ever written and as such it is written
slightly differently than other OLE Documents. If a Word command does
not return a value, you should use the &quot;InvokeNoReply&quot;
variations of invoke. For most other OLE Objects, you can always use
&quot;invoke&quot; even if there is no value returned.</p>
<p><b>Further Reading</b>: MSDN Library: Books-&gt;Inside
OLE-&gt;Chapter 14->The Mechanics of OLE Automation->The IDispatch
<h3>Events and Property changes in Controls</h3>
<p><b>addEventListener</b> &ndash; allows the user to listen for Events on
the Control.</p>
// Respond to ProgressChange events in the Web Browser by updating the applications Progress bar
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
OleAutomation automation = new OleAutomation(controlSite);
int ProgressChange = 108; //0x6C - obtained from the type library
ProgressBar progressBar = new ProgressBar(shell, SWT.BORDER);
controlSite.addEventListener(ProgressChange, new OleListener() {
public void handleEvent(OleEvent event) {
if (event.detail != ProgressChange) return;
Variant progress = event.arguments[0];
Variant maxProgress = event.arguments[1];
if (progress == null || maxProgress == null) return;
<p>Note: The application must know the identifier for the event
(ProgressChange) and what kind of data it is being given in the <tt>event.argument</tt>
(In our example <tt>event.arguments[0]</tt> is the current progress
value and <tt>event.arguments[1]</tt> is the maximum progress
value)&ndash; You can find this out from the type library:</p>
dispinterface DWebBrowserEvents {
[id(0x0000006c), helpstring(&quot;Fired when download progress is updated.&quot;)]
void ProgressChange(
[in] long Progress,&nbsp;
[in] long ProgressMax);
<p><b>addPropertyListener</b> &ndash; allows the user to be notified
before property changes occur&mdash;with the option to veto the
change&mdash;and after property change has occurred.</p>
OleControlSite controlSite = new OleControlSite(frame, SWT.NONE, &quot;Shell.Explorer&quot;);
OleAutomation automation = new OleAutomation(controlSite);
int[] rgdispid = automation.getIDsOfNames(new String[]{&quot;ReadyState&quot;});
int READYSTATE = rgdispid[0];
// Listen for changes to the ready state and print out the current state
controlSite.addPropertyListener(READYSTATE, new OleListener() {
public void handleEvent(OleEvent event) {
if (event.detail == OLE.PROPERTY_CHANGING) {
// Print out the old state
Variant state = automation.getProperty(READYSTATE);
System.out.println(&quot;Web State changing from &quot; + state.getInt());
event.doit = true; // allow property change to happen
if (event.detail == OLE.PROPERTY_CHANGED) {
Variant state = automation.getProperty(READYSTATE);
System.out.println(&quot;Web State changed to &quot; + state.getInt());
<p>You can listen for a change to any property defined in the type
<p>The type library also contains enumerations that can be used to
interpret the property values. For example the &quot;ReadyState&quot;
values in the previous example are integer values belonging to the
following enumeration:</p>
typedef enum {
<p>On the Windows platform, adding OLE Objects to your application
expands the user experience. SWT makes this easy to do by allowing OLE
Objects to be embedded in SWT <i>Container</i> widgets, making the
Object's interface available to your application, and therefore to your
<div class="notices">
<p>Microsoft, Windows, Windows NT, and the Windows logo are
trademarks of Microsoft Corporation in the United States, other
countries, or both.</p>