blob: 0de9c0fd1f715d2af7450c0bf8f3e84ae75ad649 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.ole.win32;
import java.io.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.ole.win32.*;
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.widgets.*;
/**
* OleControlSite provides a site to manage an embedded ActiveX Control within a container.
*
* <p>In addition to the behaviour provided by OleClientSite, this object provides the following:
* <ul>
* <li>events from the ActiveX control
* <li>notification of property changes from the ActiveX control
* <li>simplified access to well known properties of the ActiveX Control (e.g. font, background color)
* <li>expose ambient properties of the container to the ActiveX Control
* </ul>
*
* <p>This object implements the OLE Interfaces IOleControlSite, IDispatch, and IPropertyNotifySink.
*
* <p>Note that although this class is a subclass of <code>Composite</code>,
* it does not make sense to add <code>Control</code> children to it,
* or set a layout on it.
* </p>
* <dl>
* <dt><b>Styles</b> <dd>BORDER
* <dt><b>Events</b> <dd>Dispose, Move, Resize
* </dl>
*
* @see <a href="http://www.eclipse.org/swt/snippets/#ole">OLE and ActiveX snippets</a>
* @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: OLEExample, OleWebBrowser</a>
*/
public class OleControlSite extends OleClientSite
{
// interfaces for this container
private COMObject iOleControlSite;
private COMObject iDispatch;
// supporting Property Change attributes
private OlePropertyChangeSink olePropertyChangeSink;
// supporting Event Sink attributes
private OleEventSink[] oleEventSink = new OleEventSink[0];
private GUID[] oleEventSinkGUID = new GUID[0];
private long[] oleEventSinkIUnknown = new long[0];
// supporting information for the Control COM object
private CONTROLINFO currentControlInfo;
private int[] sitePropertyIds = new int[0];
private Variant[] sitePropertyValues = new Variant[0];
private Font font;
// work around for IE destroying the caret
static int SWT_RESTORECARET;
static final String SHELL_PROG_ID = "Shell.Explorer"; //$NON-NLS-1$
/**
* Create an OleControlSite child widget using the OLE Document type associated with the
* specified file. The OLE Document type is determined either through header information in the file
* or through a Registry entry for the file extension. Use style bits to select a particular look
* or set of properties.
*
* @param parent a composite widget; must be an OleFrame
* @param style the bitwise OR'ing of widget styles
* @param file the file that is to be opened in this OLE Document
*
* @exception IllegalArgumentException
* <ul><li>ERROR_NULL_ARGUMENT when the parent is null
* <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame</ul>
* @exception SWTException
* <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
* <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
* <li>ERROR_CANNOT_OPEN_FILE when failed to open file
* <li>ERROR_INTERFACE_NOT_FOUND when unable to create callbacks for OLE Interfaces
* <li>ERROR_INVALID_CLASSID
* </ul>
*
* @since 3.5
*/
public OleControlSite(Composite parent, int style, File file) {
super(parent, style, file);
// Init site properties
setSiteProperty(COM.DISPID_AMBIENT_USERMODE, new Variant(true));
setSiteProperty(COM.DISPID_AMBIENT_UIDEAD, new Variant(false));
}
/**
* Create an OleControlSite child widget using style bits
* to select a particular look or set of properties.
*
* @param parent a composite widget; must be an OleFrame
* @param style the bitwise OR'ing of widget styles
* @param progId the unique program identifier which has been registered for this ActiveX Control;
* the value of the ProgID key or the value of the VersionIndependentProgID key specified
* in the registry for this Control (for example, the VersionIndependentProgID for
* Internet Explorer is Shell.Explorer)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when the parent is null
*</ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
* <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
* <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
* <li>ERROR_CANNOT_ACCESS_CLASSFACTORY when Class Factory could not be found
* <li>ERROR_CANNOT_CREATE_LICENSED_OBJECT when failed to create a licensed OLE Object
* </ul>
*/
public OleControlSite(Composite parent, int style, String progId) {
super(parent, style);
try {
// check for licensing
appClsid = getClassID(progId);
if (appClsid == null) OLE.error(OLE.ERROR_INVALID_CLASSID);
long licinfo = getLicenseInfo(appClsid);
if (licinfo == 0) {
// Open a storage object
tempStorage = createTempStorage();
// Create ole object with storage object
long[] address = new long[1];
/*
* Bug in ICA Client 2.7. The creation of the IOleObject fails if the client
* site is provided to OleCreate(). The fix is to detect that the program
* id is an ICA Client and do not pass a client site to OleCreate().
* IOleObject.SetClientSite() is called later on.
*/
long clientSite = isICAClient() ? 0 : iOleClientSite.getAddress();
int result = COM.OleCreate(appClsid, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, clientSite, tempStorage.getAddress(), address);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
objIUnknown = new IUnknown(address[0]);
} else {
// Prepare the ClassFactory
long[] ppvObject = new long[1];
try {
int result = COM.CoGetClassObject(appClsid, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, 0, COM.IIDIClassFactory2, ppvObject);
if (result != COM.S_OK) {
OLE.error(OLE.ERROR_CANNOT_ACCESS_CLASSFACTORY, result);
}
IClassFactory2 classFactory = new IClassFactory2(ppvObject[0]);
// Create Com Object
ppvObject = new long[1];
result = classFactory.CreateInstanceLic(0, 0, COM.IIDIUnknown, licinfo, ppvObject);
classFactory.Release();
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_LICENSED_OBJECT, result);
} finally {
COM.SysFreeString(licinfo);
}
objIUnknown = new IUnknown(ppvObject[0]);
// Prepare a storage medium
ppvObject = new long[1];
if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppvObject) == COM.S_OK) {
IPersistStorage persist = new IPersistStorage(ppvObject[0]);
tempStorage = createTempStorage();
persist.InitNew(tempStorage.getAddress());
persist.Release();
}
}
// Init sinks
addObjectReferences();
// Init site properties
setSiteProperty(COM.DISPID_AMBIENT_USERMODE, new Variant(true));
setSiteProperty(COM.DISPID_AMBIENT_UIDEAD, new Variant(false));
if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state= STATE_RUNNING;
} catch (SWTError e) {
dispose();
disposeCOMInterfaces();
throw e;
}
}
/**
* Create an OleClientSite child widget to edit the specified file using the specified OLE Document
* application. Use style bits to select a particular look or set of properties.
* <p>
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public
* API for <code>OleClientSite</code>. It is marked public only so that it
* can be shared within the packages provided by SWT. It is not
* available on all platforms, and should never be called from
* application code.
* </p>
* @param parent a composite widget; must be an OleFrame
* @param style the bitwise OR'ing of widget styles
* @param progId the unique program identifier of am OLE Document application;
* the value of the ProgID key or the value of the VersionIndependentProgID key specified
* in the registry for the desired OLE Document (for example, the VersionIndependentProgID
* for Word is Word.Document)
* @param file the file that is to be opened in this OLE Document
*
* @exception IllegalArgumentException
* <ul><li>ERROR_NULL_ARGUMENT when the parent is null
* <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame</ul>
* @exception SWTException
* <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
* <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
* <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
* <li>ERROR_CANNOT_OPEN_FILE when failed to open file
* </ul>
*
* @noreference This method is not intended to be referenced by clients.
*
* @since 3.5
*/
public OleControlSite(Composite parent, int style, String progId, File file) {
super(parent, style, progId, file);
// Init site properties
setSiteProperty(COM.DISPID_AMBIENT_USERMODE, new Variant(true));
setSiteProperty(COM.DISPID_AMBIENT_UIDEAD, new Variant(false));
}
/**
* Adds the listener to receive events.
*
* @param eventID the id of the event
*
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
public void addEventListener(int eventID, OleListener listener) {
if (listener == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
GUID riid = getDefaultEventSinkGUID(objIUnknown);
if (riid != null) {
addEventListener(objIUnknown.getAddress(), riid, eventID, listener);
}
}
static GUID getDefaultEventSinkGUID(IUnknown unknown) {
// get Event Sink I/F from IProvideClassInfo2
long[] ppvObject = new long[1];
if (unknown.QueryInterface(COM.IIDIProvideClassInfo2, ppvObject) == COM.S_OK) {
IProvideClassInfo2 pci2 = new IProvideClassInfo2(ppvObject[0]);
GUID riid = new GUID();
int result = pci2.GetGUID(COM.GUIDKIND_DEFAULT_SOURCE_DISP_IID, riid);
pci2.Release();
if (result == COM.S_OK) return riid;
}
// get Event Sink I/F from IProvideClassInfo
if (unknown.QueryInterface(COM.IIDIProvideClassInfo, ppvObject) == COM.S_OK) {
IProvideClassInfo pci = new IProvideClassInfo(ppvObject[0]);
long[] ppTI = new long[1];
long[] ppEI = new long[1];
int result = pci.GetClassInfo(ppTI);
pci.Release();
if (result == COM.S_OK && ppTI[0] != 0) {
ITypeInfo classInfo = new ITypeInfo(ppTI[0]);
long[] ppTypeAttr = new long[1];
result = classInfo.GetTypeAttr(ppTypeAttr);
if (result == COM.S_OK && ppTypeAttr[0] != 0) {
TYPEATTR typeAttribute = new TYPEATTR();
COM.MoveMemory(typeAttribute, ppTypeAttr[0], TYPEATTR.sizeof);
classInfo.ReleaseTypeAttr(ppTypeAttr[0]);
int implMask = COM.IMPLTYPEFLAG_FDEFAULT | COM.IMPLTYPEFLAG_FSOURCE | COM.IMPLTYPEFLAG_FRESTRICTED;
int implBits = COM.IMPLTYPEFLAG_FDEFAULT | COM.IMPLTYPEFLAG_FSOURCE;
for (int i = 0; i < typeAttribute.cImplTypes; i++) {
int[] pImplTypeFlags = new int[1];
if (classInfo.GetImplTypeFlags(i, pImplTypeFlags) == COM.S_OK) {
if ((pImplTypeFlags[0] & implMask) == implBits) {
int[] pRefType = new int[1];
if (classInfo.GetRefTypeOfImplType(i, pRefType) == COM.S_OK) {
classInfo.GetRefTypeInfo(pRefType[0], ppEI);
}
}
}
}
}
classInfo.Release();
if (ppEI[0] != 0) {
ITypeInfo eventInfo = new ITypeInfo(ppEI[0]);
ppTypeAttr = new long[1];
result = eventInfo.GetTypeAttr(ppTypeAttr);
GUID riid = null;
if (result == COM.S_OK && ppTypeAttr[0] != 0) {
riid = new GUID();
COM.MoveMemory(riid, ppTypeAttr[0], GUID.sizeof);
eventInfo.ReleaseTypeAttr(ppTypeAttr[0]);
}
eventInfo.Release();
return riid;
}
}
}
return null;
}
/**
* Adds the listener to receive events.
*
* @since 2.0
*
* @param automation the automation object that provides the event notification
* @param eventID the id of the event
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
public void addEventListener(OleAutomation automation, int eventID, OleListener listener) {
if (listener == null || automation == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
long address = automation.getAddress();
IUnknown unknown = new IUnknown(address);
GUID riid = getDefaultEventSinkGUID(unknown);
if (riid != null) {
addEventListener(address, riid, eventID, listener);
}
}
/**
* Adds the listener to receive events.
*
* @since 3.2
*
* @param automation the automation object that provides the event notification
* @param eventSinkId the GUID of the event sink
* @param eventID the id of the event
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
public void addEventListener(OleAutomation automation, String eventSinkId, int eventID, OleListener listener) {
if (listener == null || automation == null || eventSinkId == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
long address = automation.getAddress();
if (address == 0) return;
char[] buffer = (eventSinkId +"\0").toCharArray();
GUID guid = new GUID();
if (COM.IIDFromString(buffer, guid) != COM.S_OK) return;
addEventListener(address, guid, eventID, listener);
}
void addEventListener(long iunknown, GUID guid, int eventID, OleListener listener) {
if (listener == null || iunknown == 0 || guid == null) OLE.error (SWT.ERROR_NULL_ARGUMENT);
// have we connected to this kind of event sink before?
int index = -1;
for (int i = 0; i < oleEventSinkGUID.length; i++) {
if (COM.IsEqualGUID(oleEventSinkGUID[i], guid)) {
if (iunknown == oleEventSinkIUnknown[i]) {
index = i;
break;
}
}
}
if (index != -1) {
oleEventSink[index].addListener(eventID, listener);
} else {
int oldLength = oleEventSink.length;
OleEventSink[] newOleEventSink = new OleEventSink[oldLength + 1];
GUID[] newOleEventSinkGUID = new GUID[oldLength + 1];
long[] newOleEventSinkIUnknown = new long[oldLength + 1];
System.arraycopy(oleEventSink, 0, newOleEventSink, 0, oldLength);
System.arraycopy(oleEventSinkGUID, 0, newOleEventSinkGUID, 0, oldLength);
System.arraycopy(oleEventSinkIUnknown, 0, newOleEventSinkIUnknown, 0, oldLength);
oleEventSink = newOleEventSink;
oleEventSinkGUID = newOleEventSinkGUID;
oleEventSinkIUnknown = newOleEventSinkIUnknown;
oleEventSink[oldLength] = new OleEventSink(this, iunknown, guid);
oleEventSinkGUID[oldLength] = guid;
oleEventSinkIUnknown[oldLength] = iunknown;
oleEventSink[oldLength].AddRef();
oleEventSink[oldLength].connect();
oleEventSink[oldLength].addListener(eventID, listener);
}
}
@Override
protected void addObjectReferences() {
super.addObjectReferences();
// Get property change notification from control
connectPropertyChangeSink();
// Get access to the Control object
long[] ppvObject = new long[1];
if (objIUnknown.QueryInterface(COM.IIDIOleControl, ppvObject) == COM.S_OK) {
IOleControl objIOleControl = new IOleControl(ppvObject[0]);
// ask the control for its info in case users
// need to act on it
currentControlInfo = new CONTROLINFO();
objIOleControl.GetControlInfo(currentControlInfo);
objIOleControl.Release();
}
}
/**
* Adds the listener to receive events.
*
* @param propertyID the identifier of the property
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
public void addPropertyListener(int propertyID, OleListener listener) {
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
olePropertyChangeSink.addListener(propertyID, listener);
}
private void connectPropertyChangeSink() {
olePropertyChangeSink = new OlePropertyChangeSink(this);
olePropertyChangeSink.AddRef();
olePropertyChangeSink.connect(objIUnknown);
}
@Override
protected void createCOMInterfaces () {
super.createCOMInterfaces();
// register each of the interfaces that this object implements
iOleControlSite = new COMObject(new int[]{2, 0, 0, 0, 1, 1, 3, 2, 1, 0}){
@Override
public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
@Override
public long method1(long[] args) {return AddRef();}
@Override
public long method2(long[] args) {return Release();}
@Override
public long method3(long[] args) {return OnControlInfoChanged();}
// method4 LockInPlaceActive - not implemented
// method5 GetExtendedControl - not implemented
// method6 TransformCoords - not implemented
// method7 Translate Accelerator - not implemented
@Override
public long method8(long[] args) {return OnFocus((int)args[0]);}
// method9 ShowPropertyFrame - not implemented
};
iDispatch = new COMObject(new int[]{2, 0, 0, 1, 3, 5, 8}){
@Override
public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
@Override
public long method1(long[] args) {return AddRef();}
@Override
public long method2(long[] args) {return Release();}
// method3 GetTypeInfoCount - not implemented
// method4 GetTypeInfo - not implemented
// method5 GetIDsOfNames - not implemented
@Override
public long method6(long[] args) {return Invoke((int)args[0], args[1], (int)args[2], (int)args[3], args[4], args[5], args[6], args[7]);}
};
}
private void disconnectEventSinks() {
for (OleEventSink sink : oleEventSink) {
sink.disconnect();
sink.Release();
}
oleEventSink = new OleEventSink[0];
oleEventSinkGUID = new GUID[0];
oleEventSinkIUnknown = new long[0];
}
private void disconnectPropertyChangeSink() {
if (olePropertyChangeSink != null) {
olePropertyChangeSink.disconnect(objIUnknown);
olePropertyChangeSink.Release();
}
olePropertyChangeSink = null;
}
@Override
protected void disposeCOMInterfaces() {
super.disposeCOMInterfaces();
if (iOleControlSite != null)
iOleControlSite.dispose();
iOleControlSite = null;
if (iDispatch != null)
iDispatch.dispose();
iDispatch = null;
}
@Override
public Color getBackground () {
if (objIUnknown != null) {
// !! We are getting the OLE_COLOR - should we change this to the COLORREF value?
OleAutomation oleObject= new OleAutomation(this);
Variant varBackColor = oleObject.getProperty(COM.DISPID_BACKCOLOR);
oleObject.dispose();
if (varBackColor != null){
int[] colorRef = new int[1];
if (COM.OleTranslateColor(varBackColor.getInt(), 0, colorRef) == COM.S_OK)
return Color.win32_new(getDisplay(), colorRef[0]);
}
}
return super.getBackground();
}
@Override
public Font getFont () {
if (font != null && !font.isDisposed()) return font;
if (objIUnknown != null) {
OleAutomation oleObject= new OleAutomation(this);
Variant varDispFont = oleObject.getProperty(COM.DISPID_FONT);
oleObject.dispose();
if (varDispFont != null){
OleAutomation iDispFont = varDispFont.getAutomation();
Variant lfFaceName = iDispFont.getProperty(COM.DISPID_FONT_NAME);
Variant lfHeight = iDispFont.getProperty(COM.DISPID_FONT_SIZE);
Variant lfItalic = iDispFont.getProperty(COM.DISPID_FONT_ITALIC);
//Variant lfCharSet = iDispFont.getProperty(COM.DISPID_FONT_CHARSET);
Variant lfBold = iDispFont.getProperty(COM.DISPID_FONT_BOLD);
iDispFont.dispose();
if (lfFaceName != null &&
lfHeight != null &&
lfItalic != null &&
lfBold != null){
int style = 3 * lfBold.getInt() + 2 * lfItalic.getInt();
font = new Font(getShell().getDisplay(), lfFaceName.getString(), lfHeight.getInt(), style);
return font;
}
}
}
return super.getFont();
}
@Override
public Color getForeground () {
if (objIUnknown != null) {
// !! We are getting the OLE_COLOR - should we change this to the COLORREF value?
OleAutomation oleObject= new OleAutomation(this);
Variant varForeColor = oleObject.getProperty(COM.DISPID_FORECOLOR);
oleObject.dispose();
if (varForeColor != null){
int[] colorRef = new int[1];
if (COM.OleTranslateColor(varForeColor.getInt(), 0, colorRef) == COM.S_OK)
return Color.win32_new(getDisplay(), colorRef[0]);
}
}
return super.getForeground();
}
protected long getLicenseInfo(GUID clsid) {
long[] ppvObject = new long[1];
if (COM.CoGetClassObject(clsid, COM.CLSCTX_INPROC_HANDLER
| COM.CLSCTX_INPROC_SERVER, 0, COM.IIDIClassFactory, ppvObject) != COM.S_OK) {
return 0;
}
long result = 0;
IUnknown unknown = new IUnknown(ppvObject[0]);
if (unknown.QueryInterface(COM.IIDIClassFactory2, ppvObject) == COM.S_OK) {
IClassFactory2 classFactory = new IClassFactory2(ppvObject[0]);
LICINFO licinfo = new LICINFO();
if (classFactory.GetLicInfo(licinfo) == COM.S_OK) {
long[] pBstrKey = new long[1];
if (licinfo != null && licinfo.fRuntimeKeyAvail) {
if (classFactory.RequestLicKey(0, pBstrKey) == COM.S_OK) {
result = pBstrKey[0];
}
}
}
classFactory.Release();
}
unknown.Release();
return result;
}
/**
*
* Get the control site property specified by the dispIdMember, or
* <code>null</code> if the dispId is not recognised.
*
* @param dispId the dispId
*
* @return the property value or <code>null</code>
*
* @since 2.1
*/
public Variant getSiteProperty(int dispId){
for (int i = 0; i < sitePropertyIds.length; i++) {
if (sitePropertyIds[i] == dispId) {
return sitePropertyValues[i];
}
}
return null;
}
@Override
protected int GetWindow(long phwnd) {
if (phwnd == 0)
return COM.E_INVALIDARG;
if (frame == null) {
OS.MoveMemory(phwnd, new long[] {0}, C.PTR_SIZEOF);
return COM.E_NOTIMPL;
}
// Copy the Window's handle into the memory passed in
OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF);
return COM.S_OK;
}
private int Invoke(int dispIdMember, long riid, int lcid, int dwFlags, long pDispParams, long pVarResult, long pExcepInfo, long pArgErr) {
if (pVarResult == 0 || dwFlags != COM.DISPATCH_PROPERTYGET) {
if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo, new long [] {0}, C.PTR_SIZEOF);
if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
return COM.DISP_E_MEMBERNOTFOUND;
}
Variant result = getSiteProperty(dispIdMember);
if (result != null) {
if (pVarResult != 0) result.getData(pVarResult);
return COM.S_OK;
}
switch (dispIdMember) {
// indicate a false result
case COM.DISPID_AMBIENT_SUPPORTSMNEMONICS :
case COM.DISPID_AMBIENT_SHOWGRABHANDLES :
case COM.DISPID_AMBIENT_SHOWHATCHING :
if (pVarResult != 0) OS.MoveMemory(pVarResult, new long [] {0}, C.PTR_SIZEOF);
if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo, new long [] {0}, C.PTR_SIZEOF);
if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
return COM.S_FALSE;
// not implemented
case COM.DISPID_AMBIENT_OFFLINEIFNOTCONNECTED :
case COM.DISPID_AMBIENT_BACKCOLOR :
case COM.DISPID_AMBIENT_FORECOLOR :
case COM.DISPID_AMBIENT_FONT :
case COM.DISPID_AMBIENT_LOCALEID :
case COM.DISPID_AMBIENT_SILENT :
case COM.DISPID_AMBIENT_MESSAGEREFLECT :
if (pVarResult != 0) OS.MoveMemory(pVarResult, new long [] {0}, C.PTR_SIZEOF);
if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo, new long [] {0}, C.PTR_SIZEOF);
if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
return COM.E_NOTIMPL;
default :
if (pVarResult != 0) OS.MoveMemory(pVarResult, new long [] {0}, C.PTR_SIZEOF);
if (pExcepInfo != 0) OS.MoveMemory(pExcepInfo,new long [] {0}, C.PTR_SIZEOF);
if (pArgErr != 0) OS.MoveMemory(pArgErr, new int[] {0}, 4);
return COM.DISP_E_MEMBERNOTFOUND;
}
}
private int OnControlInfoChanged() {
long[] ppvObject = new long[1];
if (objIUnknown.QueryInterface(COM.IIDIOleControl, ppvObject) == COM.S_OK) {
IOleControl objIOleControl = new IOleControl(ppvObject[0]);
// ask the control for its info in case users
// need to act on it
currentControlInfo = new CONTROLINFO();
objIOleControl.GetControlInfo(currentControlInfo);
objIOleControl.Release();
}
return COM.S_OK;
}
@Override
protected int OnUIDeactivate(int fUndoable) {
return super.OnUIDeactivate(fUndoable);
}
@Override
void onFocusIn(Event e) {
String progID = getProgramID();
if (progID == null) return;
if (!progID.startsWith(SHELL_PROG_ID)) {
super.onFocusIn(e);
return;
}
if (objIOleInPlaceObject == null) return;
if (!isActivated) doVerb(OLE.OLEIVERB_UIACTIVATE);
if (isFocusControl()) return;
long[] phwnd = new long[1];
objIOleInPlaceObject.GetWindow(phwnd);
if (phwnd[0] == 0) return;
OS.SetFocus(phwnd[0]);
}
@Override
void onFocusOut(Event e) {
if (objIOleInPlaceObject == null) return;
String progID = getProgramID();
if (progID == null) return;
if (!progID.startsWith(SHELL_PROG_ID)) {
super.onFocusOut(e);
return;
}
/*
* FocusOut is received when focus is reassigned between handles within
* our site. In such cases the site should not be UIDeactivated.
*/
if (isFocusControl()) return;
/*
* Bug in Windows. When IE7 loses focus and UIDeactivate()
* is called, IE destroys the caret even though it is
* no longer owned by IE. If focus has moved to a control
* that shows a caret then the caret disappears. The fix
* is to detect this case and restore the caret.
*/
int threadId = OS.GetCurrentThreadId();
GUITHREADINFO lpgui1 = new GUITHREADINFO();
lpgui1.cbSize = GUITHREADINFO.sizeof;
OS.GetGUIThreadInfo(threadId, lpgui1);
objIOleInPlaceObject.UIDeactivate();
if (SWT_RESTORECARET == 0) {
SWT_RESTORECARET = OS.RegisterWindowMessage (new TCHAR (0, "SWT_RESTORECARET", true));
}
if (lpgui1.hwndCaret != 0) {
GUITHREADINFO lpgui2 = new GUITHREADINFO();
lpgui2.cbSize = GUITHREADINFO.sizeof;
OS.GetGUIThreadInfo(threadId, lpgui2);
if (lpgui2.hwndCaret == 0 && lpgui1.hwndCaret == OS.GetFocus()) {
/*
* If the caret was not restored by SWT, put it back using
* the information from GUITHREADINFO. Note that this will
* not be correct when the caret has a bitmap. There is no
* API to query the bitmap that the caret is using.
*/
if (OS.SendMessage (lpgui1.hwndCaret, SWT_RESTORECARET, 0, 0) == 0) {
int width = lpgui1.right - lpgui1.left;
int height = lpgui1.bottom - lpgui1.top;
OS.CreateCaret (lpgui1.hwndCaret, 0, width, height);
OS.SetCaretPos (lpgui1.left, lpgui1.top);
OS.ShowCaret (lpgui1.hwndCaret);
}
}
} else if (lpgui1.hwndFocus != 0 && lpgui1.hwndFocus == OS.GetFocus()) {
OS.SendMessage (lpgui1.hwndFocus, SWT_RESTORECARET, 0, 0);
}
}
private int OnFocus(int fGotFocus) {
return COM.S_OK;
}
@Override
protected int QueryInterface(long riid, long ppvObject) {
int result = super.QueryInterface(riid, ppvObject);
if (result == COM.S_OK)
return result;
if (riid == 0 || ppvObject == 0)
return COM.E_INVALIDARG;
GUID guid = new GUID();
COM.MoveMemory(guid, riid, GUID.sizeof);
if (COM.IsEqualGUID(guid, COM.IIDIOleControlSite)) {
OS.MoveMemory(ppvObject, new long[] {iOleControlSite.getAddress()}, C.PTR_SIZEOF);
AddRef();
return COM.S_OK;
}
if (COM.IsEqualGUID(guid, COM.IIDIDispatch)) {
OS.MoveMemory(ppvObject, new long[] {iDispatch.getAddress()}, C.PTR_SIZEOF);
AddRef();
return COM.S_OK;
}
OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
return COM.E_NOINTERFACE;
}
@Override
protected int Release() {
int result = super.Release();
if (result == 0) {
for (int i = 0; i < sitePropertyIds.length; i++) {
sitePropertyValues[i].dispose();
}
sitePropertyIds = new int[0];
sitePropertyValues = new Variant[0];
}
return result;
}
@Override
protected void releaseObjectInterfaces() {
disconnectEventSinks();
disconnectPropertyChangeSink();
super.releaseObjectInterfaces();
}
/**
* Removes the listener.
*
* @param eventID the event identifier
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
public void removeEventListener(int eventID, OleListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
GUID riid = getDefaultEventSinkGUID(objIUnknown);
if (riid != null) {
removeEventListener(objIUnknown.getAddress(), riid, eventID, listener);
}
}
/**
* Removes the listener.
*
* @since 2.0
* @deprecated - use OleControlSite.removeEventListener(OleAutomation, int, OleListener)
*
* @param automation the automation object that provides the event notification
*
* @param guid the identifier of the events COM interface
*
* @param eventID the event identifier
*
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
@Deprecated
public void removeEventListener(OleAutomation automation, GUID guid, int eventID, OleListener listener) {
checkWidget();
if (automation == null || listener == null || guid == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
removeEventListener(automation.getAddress(), guid, eventID, listener);
}
/**
* Removes the listener.
*
* @param automation the automation object that provides the event notification
* @param eventID the event identifier
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*
* @since 2.0
*/
public void removeEventListener(OleAutomation automation, int eventID, OleListener listener) {
checkWidget();
if (automation == null || listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
long address = automation.getAddress();
IUnknown unknown = new IUnknown(address);
GUID riid = getDefaultEventSinkGUID(unknown);
if (riid != null) {
removeEventListener(address, riid, eventID, listener);
}
}
void removeEventListener(long iunknown, GUID guid, int eventID, OleListener listener) {
if (listener == null || guid == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
for (int i = 0; i < oleEventSink.length; i++) {
if (COM.IsEqualGUID(oleEventSinkGUID[i], guid)) {
if (iunknown == oleEventSinkIUnknown[i]) {
oleEventSink[i].removeListener(eventID, listener);
if (!oleEventSink[i].hasListeners()) {
//free resources associated with event sink
oleEventSink[i].disconnect();
oleEventSink[i].Release();
int oldLength = oleEventSink.length;
if (oldLength == 1) {
oleEventSink = new OleEventSink[0];
oleEventSinkGUID = new GUID[0];
oleEventSinkIUnknown = new long[0];
} else {
OleEventSink[] newOleEventSink = new OleEventSink[oldLength - 1];
System.arraycopy(oleEventSink, 0, newOleEventSink, 0, i);
System.arraycopy(oleEventSink, i + 1, newOleEventSink, i, oldLength - i - 1);
oleEventSink = newOleEventSink;
GUID[] newOleEventSinkGUID = new GUID[oldLength - 1];
System.arraycopy(oleEventSinkGUID, 0, newOleEventSinkGUID, 0, i);
System.arraycopy(oleEventSinkGUID, i + 1, newOleEventSinkGUID, i, oldLength - i - 1);
oleEventSinkGUID = newOleEventSinkGUID;
long[] newOleEventSinkIUnknown = new long[oldLength - 1];
System.arraycopy(oleEventSinkIUnknown, 0, newOleEventSinkIUnknown, 0, i);
System.arraycopy(oleEventSinkIUnknown, i + 1, newOleEventSinkIUnknown, i, oldLength - i - 1);
oleEventSinkIUnknown = newOleEventSinkIUnknown;
}
}
return;
}
}
}
}
/**
* Removes the listener.
*
* @param propertyID the identifier of the property
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT when listener is null</li>
* </ul>
*/
public void removePropertyListener(int propertyID, OleListener listener) {
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
olePropertyChangeSink.removeListener(propertyID, listener);
}
@Override
public void setBackground (Color color) {
super.setBackground(color);
//set the background of the ActiveX Control
if (objIUnknown != null) {
OleAutomation oleObject= new OleAutomation(this);
oleObject.setProperty(COM.DISPID_BACKCOLOR, new Variant(color.handle));
oleObject.dispose();
}
}
@Override
public void setFont (Font font) {
super.setFont(font);
//set the font of the ActiveX Control
if (objIUnknown != null) {
OleAutomation oleObject= new OleAutomation(this);
Variant varDispFont = oleObject.getProperty(COM.DISPID_FONT);
oleObject.dispose();
if (varDispFont != null){
OleAutomation iDispFont = varDispFont.getAutomation();
FontData[] fdata = font.getFontData();
iDispFont.setProperty(COM.DISPID_FONT_NAME, new Variant(fdata[0].getName()));
iDispFont.setProperty(COM.DISPID_FONT_SIZE, new Variant(fdata[0].getHeight()));
iDispFont.setProperty(COM.DISPID_FONT_ITALIC, new Variant(fdata[0].getStyle() & SWT.ITALIC));
//iDispFont.setProperty(COM.DISPID_FONT_CHARSET, new Variant(fdata[0].getCharset));
iDispFont.setProperty(COM.DISPID_FONT_BOLD, new Variant((fdata[0].getStyle() & SWT.BOLD)));
iDispFont.dispose();
}
}
this.font = font;
return;
}
@Override
public void setForeground (Color color) {
super.setForeground(color);
//set the foreground of the ActiveX Control
if (objIUnknown != null) {
OleAutomation oleObject= new OleAutomation(this);
oleObject.setProperty(COM.DISPID_FORECOLOR, new Variant(color.handle));
oleObject.dispose();
}
}
/**
* Sets the control site property specified by the dispIdMember to a new value.
* The value will be disposed by the control site when it is no longer required
* using Variant.dispose. Passing a value of null will clear the dispId value.
*
* @param dispId the ID of the property as specified by the IDL of the ActiveX Control
* @param value The new value for the property as expressed in a Variant.
*
* @since 2.1
*/
public void setSiteProperty(int dispId, Variant value){
for (int i = 0; i < sitePropertyIds.length; i++) {
if (sitePropertyIds[i] == dispId) {
if (sitePropertyValues[i] != null) {
sitePropertyValues[i].dispose();
}
if (value != null) {
sitePropertyValues[i] = value;
} else {
int oldLength = sitePropertyIds.length;
int[] newSitePropertyIds = new int[oldLength - 1];
Variant[] newSitePropertyValues = new Variant[oldLength - 1];
System.arraycopy(sitePropertyIds, 0, newSitePropertyIds, 0, i);
System.arraycopy(sitePropertyIds, i + 1, newSitePropertyIds, i, oldLength - i - 1);
System.arraycopy(sitePropertyValues, 0, newSitePropertyValues, 0, i);
System.arraycopy(sitePropertyValues, i + 1, newSitePropertyValues, i, oldLength - i - 1);
sitePropertyIds = newSitePropertyIds;
sitePropertyValues = newSitePropertyValues;
}
return;
}
}
int oldLength = sitePropertyIds.length;
int[] newSitePropertyIds = new int[oldLength + 1];
Variant[] newSitePropertyValues = new Variant[oldLength + 1];
System.arraycopy(sitePropertyIds, 0, newSitePropertyIds, 0, oldLength);
System.arraycopy(sitePropertyValues, 0, newSitePropertyValues, 0, oldLength);
newSitePropertyIds[oldLength] = dispId;
newSitePropertyValues[oldLength] = value;
sitePropertyIds = newSitePropertyIds;
sitePropertyValues = newSitePropertyValues;
}
}