| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * 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.*; |
| /** |
| * OleClientSite provides a site to manage an embedded OLE Document within a container. |
| * |
| * <p>The OleClientSite provides the following capabilities: |
| * <ul> |
| * <li>creates the in-place editor for a blank document or opening an existing OLE Document |
| * <li>lays the editor out |
| * <li>provides a mechanism for activating and deactivating the Document |
| * <li>provides a mechanism for saving changes made to the document |
| * </ul> |
| * |
| * <p>This object implements the OLE Interfaces IUnknown, IOleClientSite, IAdviseSink, |
| * IOleInPlaceSite |
| * |
| * <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><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 OleClientSite extends Composite { |
| |
| // Interfaces for this Ole Client Container |
| private COMObject iUnknown; |
| COMObject iOleClientSite; |
| private COMObject iAdviseSink; |
| private COMObject iOleInPlaceSite; |
| private COMObject iOleDocumentSite; |
| |
| protected GUID appClsid; |
| private GUID objClsid; |
| private int refCount; |
| |
| // References to the associated Frame. |
| protected OleFrame frame; |
| |
| // Access to the embedded/linked Ole Object |
| protected IUnknown objIUnknown; |
| protected IOleObject objIOleObject; |
| protected IViewObject2 objIViewObject2; |
| protected IOleInPlaceObject objIOleInPlaceObject; |
| protected IOleCommandTarget objIOleCommandTarget; |
| protected IOleDocumentView objDocumentView; |
| |
| // Related storage information |
| protected IStorage tempStorage; // IStorage interface of the receiver |
| |
| // Internal state and style information |
| private int aspect; // the display aspect of the embedded object, e.g., DvaspectContent or DvaspectIcon |
| private int type; // Indicates the type of client that can be supported inside this container |
| private boolean isStatic; // Indicates item's display is static, i.e., a bitmap, metafile, etc. |
| boolean isActivated; |
| |
| private RECT borderWidths = new RECT(); |
| private RECT indent = new RECT(); |
| private boolean inUpdate = false; |
| private boolean inInit = true; |
| private boolean inDispose = false; |
| |
| private static final String WORDPROGID = "Word.Document"; //$NON-NLS-1$ |
| |
| private Listener listener; |
| |
| static final int STATE_NONE = 0; |
| static final int STATE_RUNNING = 1; |
| static final int STATE_INPLACEACTIVE = 2; |
| static final int STATE_UIACTIVE = 3; |
| static final int STATE_ACTIVE = 4; |
| int state = STATE_NONE; |
| |
| protected OleClientSite(Composite parent, int style) { |
| /* |
| * NOTE: this constructor should never be used by itself because it does |
| * not create an Ole Object |
| */ |
| super(parent, style); |
| |
| createCOMInterfaces(); |
| |
| // install the Ole Frame for this Client Site |
| while (parent != null) { |
| if (parent instanceof OleFrame){ |
| frame = (OleFrame)parent; |
| break; |
| } |
| parent = parent.getParent(); |
| } |
| if (frame == null) OLE.error(SWT.ERROR_INVALID_ARGUMENT); |
| frame.AddRef(); |
| |
| aspect = COM.DVASPECT_CONTENT; |
| type = COM.OLEEMBEDDED; |
| isStatic = false; |
| |
| listener = new Listener() { |
| private int nestedFocusEvents = 0; |
| @Override |
| public void handleEvent(Event e) { |
| switch (e.type) { |
| case SWT.Resize : |
| case SWT.Move : onResize(e); break; |
| case SWT.Dispose : onDispose(e); break; |
| case SWT.FocusIn: |
| nestedFocusEvents++; |
| boolean hasFocus = isFocusControl(); |
| onFocusIn(e); |
| nestedFocusEvents--; |
| /* |
| * Added additional check below to avoid calling OleFrame#onFocusIn() twice, |
| * which other wise lead to Main Menu refresh problem as seen in bug 527268 |
| */ |
| if (nestedFocusEvents == 0 && hasFocus == isFocusControl()) |
| frame.onFocusIn(e); |
| break; |
| case SWT.FocusOut: |
| nestedFocusEvents++; |
| onFocusOut(e); |
| nestedFocusEvents--; |
| if (nestedFocusEvents == 0) |
| frame.onFocusOut(e); |
| break; |
| case SWT.Paint: onPaint(e); break; |
| case SWT.Traverse: onTraverse(e); break; |
| case SWT.KeyDown: /* required for traversal */ break; |
| case SWT.Activate: isActivated = true; break; |
| case SWT.Deactivate: isActivated = false; break; |
| default : |
| OLE.error(SWT.ERROR_NOT_IMPLEMENTED); |
| } |
| } |
| }; |
| |
| frame.addListener(SWT.Resize, listener); |
| frame.addListener(SWT.Move, listener); |
| addListener(SWT.Dispose, listener); |
| addListener(SWT.FocusIn, listener); |
| addListener(SWT.FocusOut, listener); |
| addListener(SWT.Paint, listener); |
| addListener(SWT.Traverse, listener); |
| addListener(SWT.KeyDown, listener); |
| addListener(SWT.Activate, listener); |
| addListener(SWT.Deactivate, listener); |
| } |
| /** |
| * Create an OleClientSite 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> |
| */ |
| public OleClientSite(Composite parent, int style, File file) { |
| this(parent, style); |
| try { |
| |
| if (file == null || file.isDirectory() || !file.exists()) |
| OLE.error(SWT.ERROR_INVALID_ARGUMENT); |
| |
| // Is there an associated CLSID? |
| GUID fileClsid = new GUID(); |
| char[] fileName = (file.getAbsolutePath()+"\0").toCharArray(); |
| int result = COM.GetClassFile(fileName, fileClsid); |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_INVALID_CLASSID, result); |
| // associated CLSID may not be installed on this machine |
| String progID = getProgID(fileClsid); |
| if (progID == null) OLE.error(OLE.ERROR_INVALID_CLASSID, result); |
| |
| appClsid = fileClsid; |
| OleCreate(appClsid, fileClsid, fileName, file); |
| } catch (SWTException e) { |
| dispose(); |
| disposeCOMInterfaces(); |
| throw e; |
| } |
| } |
| /** |
| * Create an OleClientSite child widget to edit a blank document using the specified OLE Document |
| * application. 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 progId the unique program identifier of an 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) |
| * |
| * @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 |
| * </ul> |
| */ |
| public OleClientSite(Composite parent, int style, String progId) { |
| this(parent, style); |
| try { |
| appClsid = getClassID(progId); |
| if (appClsid == null) |
| OLE.error(OLE.ERROR_INVALID_CLASSID); |
| |
| // Open a temporary storage object |
| tempStorage = createTempStorage(); |
| |
| // Create ole object with storage object |
| long /*int*/[] address = new long /*int*/[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 /*int*/ 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]); |
| |
| // Init sinks |
| addObjectReferences(); |
| |
| if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING; |
| |
| } catch (SWTException 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. |
| */ |
| public OleClientSite(Composite parent, int style, String progId, File file) { |
| this(parent, style); |
| try { |
| if (file == null || file.isDirectory() || !file.exists()) OLE.error(SWT.ERROR_INVALID_ARGUMENT); |
| appClsid = getClassID(progId); |
| if (appClsid == null) OLE.error(OLE.ERROR_INVALID_CLASSID); |
| |
| // Are we opening this file with the preferred OLE object? |
| char[] fileName = (file.getAbsolutePath()+"\0").toCharArray(); |
| GUID fileClsid = new GUID(); |
| COM.GetClassFile(fileName, fileClsid); |
| |
| OleCreate(appClsid, fileClsid, fileName, file); |
| } catch (SWTException e) { |
| dispose(); |
| disposeCOMInterfaces(); |
| throw e; |
| } |
| } |
| |
| void OleCreate(GUID appClsid, GUID fileClsid, char[] fileName, File file) { |
| |
| /* Bug in Windows. In some machines running Windows Vista and |
| * Office 2007, OleCreateFromFile() fails to open files from |
| * Office Word 97 - 2003 and in some other cases it fails to |
| * save files due to a lock. The fix is to detect this case and |
| * create the activeX using CoCreateInstance(). |
| */ |
| boolean isOffice2007 = isOffice2007(true); |
| if (!isOffice2007 && COM.IsEqualGUID(appClsid, fileClsid)){ |
| // Using the same application that created file, therefore, use default mechanism. |
| tempStorage = createTempStorage(); |
| // Create ole object with storage object |
| long /*int*/[] address = new long /*int*/[1]; |
| int result = COM.OleCreateFromFile(appClsid, fileName, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, iOleClientSite.getAddress(), tempStorage.getAddress(), address); |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result); |
| objIUnknown = new IUnknown(address[0]); |
| } else { |
| // Not using the same application that created file, therefore, copy from original file to a new storage file |
| IStorage storage = null; |
| if (COM.StgIsStorageFile(fileName) == COM.S_OK) { |
| long /*int*/[] address = new long /*int*/[1]; |
| int mode = COM.STGM_READ | COM.STGM_TRANSACTED | COM.STGM_SHARE_EXCLUSIVE; |
| int result = COM.StgOpenStorage(fileName, 0, mode, 0, 0, address); //Does an AddRef if successful |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result); |
| storage = new IStorage(address[0]); |
| } else { |
| // Original file is not a Storage file so copy contents to a stream in a new storage file |
| long /*int*/[] address = new long /*int*/[1]; |
| int mode = COM.STGM_READWRITE | COM.STGM_DIRECT | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE; |
| int result = COM.StgCreateDocfile(null, mode | COM.STGM_DELETEONRELEASE, 0, address); // Increments ref count if successful |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result); |
| storage = new IStorage(address[0]); |
| // Create a stream on the storage object. |
| // Word does not follow the standard and does not use "CONTENTS" as the name of |
| // its primary stream |
| String streamName = "CONTENTS"; //$NON-NLS-1$ |
| GUID wordGUID = getClassID(WORDPROGID); |
| if (wordGUID != null && COM.IsEqualGUID(appClsid, wordGUID)) streamName = "WordDocument"; //$NON-NLS-1$ |
| if (isOffice2007) streamName = "Package"; //$NON-NLS-1$ |
| address = new long /*int*/[1]; |
| result = storage.CreateStream(streamName, mode, 0, 0, address); // Increments ref count if successful |
| if (result != COM.S_OK) { |
| storage.Release(); |
| OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result); |
| } |
| IStream stream = new IStream(address[0]); |
| try { |
| // Copy over data in file to named stream |
| FileInputStream fileInput = new FileInputStream(file); |
| int increment = 1024*4; |
| byte[] buffer = new byte[increment]; |
| int count = 0; |
| while((count = fileInput.read(buffer)) > 0){ |
| long /*int*/ pv = OS.CoTaskMemAlloc(count); |
| OS.MoveMemory(pv, buffer, count); |
| result = stream.Write(pv, count, null) ; |
| OS.CoTaskMemFree(pv); |
| if (result != COM.S_OK) { |
| fileInput.close(); |
| stream.Release(); |
| storage.Release(); |
| OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result); |
| } |
| } |
| fileInput.close(); |
| stream.Commit(COM.STGC_DEFAULT); |
| stream.Release(); |
| } catch (IOException err) { |
| stream.Release(); |
| storage.Release(); |
| OLE.error(OLE.ERROR_CANNOT_OPEN_FILE); |
| } |
| } |
| |
| // Open a temporary storage object |
| tempStorage = createTempStorage(); |
| // Copy over contents of file |
| int result = storage.CopyTo(0, null, null, tempStorage.getAddress()); |
| storage.Release(); |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result); |
| |
| // create ole client |
| long /*int*/[] ppv = new long /*int*/[1]; |
| result = COM.CoCreateInstance(appClsid, 0, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, COM.IIDIUnknown, ppv); |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result); |
| objIUnknown = new IUnknown(ppv[0]); |
| // get the persistent storage of the ole client |
| ppv = new long /*int*/[1]; |
| result = objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv); |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result); |
| IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]); |
| // load the contents of the file into the ole client site |
| result = iPersistStorage.Load(tempStorage.getAddress()); |
| iPersistStorage.Release(); |
| if (result != COM.S_OK)OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result); |
| } |
| |
| // Init sinks |
| addObjectReferences(); |
| |
| if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING; |
| } |
| protected void addObjectReferences() { |
| // |
| long /*int*/[] ppvObject = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIPersist, ppvObject) == COM.S_OK) { |
| IPersist objIPersist = new IPersist(ppvObject[0]); |
| GUID tempid = new GUID(); |
| if (objIPersist.GetClassID(tempid) == COM.S_OK) |
| objClsid = tempid; |
| objIPersist.Release(); |
| } |
| |
| // |
| ppvObject = new long /*int*/[1]; |
| int result = objIUnknown.QueryInterface(COM.IIDIViewObject2, ppvObject); |
| if (result != COM.S_OK) |
| OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND, result); |
| objIViewObject2 = new IViewObject2(ppvObject[0]); |
| objIViewObject2.SetAdvise(aspect, 0, iAdviseSink.getAddress()); |
| |
| // |
| ppvObject = new long /*int*/[1]; |
| result = objIUnknown.QueryInterface(COM.IIDIOleObject, ppvObject); |
| if (result != COM.S_OK) |
| OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND, result); |
| objIOleObject = new IOleObject(ppvObject[0]); |
| /* |
| * Feature in Windows. Despite the fact that the clientSite was provided during the |
| * creation of the OleObject (which is required by WMP11 - see bug 173556), |
| * some applications choose to ignore this optional parameter (see bug 211663) |
| * during OleCreate. The fix is to check whether the clientSite has already been set |
| * and set it. Note that setting it twice can result in assert failures. |
| */ |
| long /*int*/[] ppvClientSite = new long /*int*/[1]; |
| result = objIOleObject.GetClientSite(ppvClientSite); |
| if (ppvClientSite[0] == 0) { |
| objIOleObject.SetClientSite(iOleClientSite.getAddress()); |
| } else { |
| Release(); // GetClientSite performs an AddRef so we must release it. |
| } |
| int[] pdwConnection = new int[1]; |
| objIOleObject.Advise(iAdviseSink.getAddress(), pdwConnection); |
| objIOleObject.SetHostNames("main", "main"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| // Notify the control object that it is embedded in an OLE container |
| COM.OleSetContainedObject(objIUnknown.getAddress(), true); |
| |
| // Is OLE object linked or embedded? |
| ppvObject = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIOleLink, ppvObject) == COM.S_OK) { |
| IOleLink objIOleLink = new IOleLink(ppvObject[0]); |
| long /*int*/[] ppmk = new long /*int*/[1]; |
| if (objIOleLink.GetSourceMoniker(ppmk) == COM.S_OK) { |
| IMoniker objIMoniker = new IMoniker(ppmk[0]); |
| objIMoniker.Release(); |
| type = COM.OLELINKED; |
| objIOleLink.BindIfRunning(); |
| } else { |
| isStatic = true; |
| } |
| objIOleLink.Release(); |
| } |
| } |
| protected int AddRef() { |
| refCount++; |
| return refCount; |
| } |
| private int CanInPlaceActivate() { |
| if (aspect == COM.DVASPECT_CONTENT && type == COM.OLEEMBEDDED) |
| return COM.S_OK; |
| |
| return COM.S_FALSE; |
| } |
| private int ContextSensitiveHelp(int fEnterMode) { |
| return COM.S_OK; |
| } |
| protected void createCOMInterfaces() { |
| |
| iUnknown = new COMObject(new int[]{2, 0, 0}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| }; |
| |
| iOleClientSite = new COMObject(new int[]{2, 0, 0, 0, 3, 1, 0, 1, 0}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| @Override |
| public long /*int*/ method3(long /*int*/[] args) {return SaveObject();} |
| // method4 GetMoniker - not implemented |
| @Override |
| public long /*int*/ method5(long /*int*/[] args) {return GetContainer(args[0]);} |
| @Override |
| public long /*int*/ method6(long /*int*/[] args) {return ShowObject();} |
| @Override |
| public long /*int*/ method7(long /*int*/[] args) {return OnShowWindow((int)/*64*/args[0]);} |
| // method8 RequestNewObjectLayout - not implemented |
| }; |
| |
| iAdviseSink = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 0, 0}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| @Override |
| public long /*int*/ method3(long /*int*/[] args) {return OnDataChange(args[0], args[1]);} |
| @Override |
| public long /*int*/ method4(long /*int*/[] args) {return OnViewChange((int)/*64*/args[0], (int)/*64*/args[1]);} |
| //method5 OnRename - not implemented |
| @Override |
| public long /*int*/ method6(long /*int*/[] args) {OnSave();return 0;} |
| @Override |
| public long /*int*/ method7(long /*int*/[] args) {return OnClose();} |
| }; |
| |
| iOleInPlaceSite = new COMObject(new int[]{2, 0, 0, 1, 1, 0, 0, 0, 5, C.PTR_SIZEOF == 4 ? 2 : 1, 1, 0, 0, 0, 1}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| @Override |
| public long /*int*/ method3(long /*int*/[] args) {return GetWindow(args[0]);} |
| @Override |
| public long /*int*/ method4(long /*int*/[] args) {return ContextSensitiveHelp((int)/*64*/args[0]);} |
| @Override |
| public long /*int*/ method5(long /*int*/[] args) {return CanInPlaceActivate();} |
| @Override |
| public long /*int*/ method6(long /*int*/[] args) {return OnInPlaceActivate();} |
| @Override |
| public long /*int*/ method7(long /*int*/[] args) {return OnUIActivate();} |
| @Override |
| public long /*int*/ method8(long /*int*/[] args) {return GetWindowContext(args[0], args[1], args[2], args[3], args[4]);} |
| @Override |
| public long /*int*/ method9(long /*int*/[] args) { |
| if (args.length == 2) { |
| return Scroll((int)/*64*/args[0], (int)/*64*/args[1]); |
| } else { |
| return Scroll_64(args[0]); |
| } |
| } |
| @Override |
| public long /*int*/ method10(long /*int*/[] args) {return OnUIDeactivate((int)/*64*/args[0]);} |
| @Override |
| public long /*int*/ method11(long /*int*/[] args) {return OnInPlaceDeactivate();} |
| // method12 DiscardUndoState - not implemented |
| // method13 DeactivateAndUndoChange - not implemented |
| @Override |
| public long /*int*/ method14(long /*int*/[] args) {return OnPosRectChange(args[0]);} |
| }; |
| |
| iOleDocumentSite = new COMObject(new int[]{2, 0, 0, 1}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| @Override |
| public long /*int*/ method3(long /*int*/[] args) {return ActivateMe(args[0]);} |
| }; |
| } |
| protected IStorage createTempStorage() { |
| long /*int*/[] tempStorage = new long /*int*/[1]; |
| int grfMode = COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_DELETEONRELEASE; |
| int result = COM.StgCreateDocfile(null, grfMode, 0, tempStorage); |
| if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_FILE, result); |
| return new IStorage(tempStorage[0]); |
| } |
| /** |
| * Deactivates an active in-place object and discards the object's undo state. |
| */ |
| public void deactivateInPlaceClient() { |
| if (objIOleInPlaceObject != null) { |
| objIOleInPlaceObject.InPlaceDeactivate(); |
| } |
| } |
| private void deleteTempStorage() { |
| //Destroy this item's contents in the temp root IStorage. |
| if (tempStorage != null){ |
| tempStorage.Release(); |
| } |
| tempStorage = null; |
| } |
| protected void disposeCOMInterfaces() { |
| if (iUnknown != null) |
| iUnknown.dispose(); |
| iUnknown = null; |
| |
| if (iOleClientSite != null) |
| iOleClientSite.dispose(); |
| iOleClientSite = null; |
| |
| if (iAdviseSink != null) |
| iAdviseSink.dispose(); |
| iAdviseSink = null; |
| |
| if (iOleInPlaceSite != null) |
| iOleInPlaceSite.dispose(); |
| iOleInPlaceSite = null; |
| |
| if (iOleDocumentSite != null) |
| iOleDocumentSite.dispose(); |
| iOleDocumentSite = null; |
| } |
| /** |
| * Requests that the OLE Document or ActiveX Control perform an action; actions are almost always |
| * changes to the activation state. |
| * |
| * @param verb the operation that is requested. This is one of the OLE.OLEIVERB_ values |
| * |
| * @return an HRESULT value indicating the success of the operation request; OLE.S_OK indicates |
| * success |
| */ |
| public int doVerb(int verb) { |
| // Not all OLE clients (for example PowerPoint) can be set into the running state in the constructor. |
| // The fix is to ensure that the client is in the running state before invoking any verb on it. |
| if (state == STATE_NONE) { |
| if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING; |
| } |
| if (state == STATE_NONE || isStatic) |
| return COM.E_FAIL; |
| |
| // See PR: 1FV9RZW |
| RECT rect = new RECT(); |
| OS.GetClientRect(handle, rect); |
| int result = objIOleObject.DoVerb(verb, null, iOleClientSite.getAddress(), 0, handle, rect); |
| |
| if (state != STATE_RUNNING && inInit) { |
| updateStorage(); |
| inInit = false; |
| } |
| return result; |
| } |
| /** |
| * Asks the OLE Document or ActiveX Control to execute a command from a standard |
| * list of commands. The OLE Document or ActiveX Control must support the IOleCommandTarget |
| * interface. The OLE Document or ActiveX Control does not have to support all the commands |
| * in the standard list. To check if a command is supported, you can call queryStatus with |
| * the cmdID. |
| * |
| * @param cmdID the ID of a command; these are the OLE.OLECMDID_ values - a small set of common |
| * commands |
| * @param options the optional flags; these are the OLE.OLECMDEXECOPT_ values |
| * @param in the argument for the command |
| * @param out the return value of the command |
| * |
| * @return an HRESULT value; OLE.S_OK is returned if successful |
| * |
| */ |
| public int exec(int cmdID, int options, Variant in, Variant out) { |
| |
| if (objIOleCommandTarget == null) { |
| long /*int*/[] address = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK) |
| return OLE.ERROR_INTERFACE_NOT_FOUND; |
| objIOleCommandTarget = new IOleCommandTarget(address[0]); |
| } |
| |
| long /*int*/ inAddress = 0; |
| if (in != null){ |
| inAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof); |
| in.getData(inAddress); |
| } |
| long /*int*/ outAddress = 0; |
| if (out != null){ |
| outAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof); |
| out.getData(outAddress); |
| } |
| |
| int result = objIOleCommandTarget.Exec(null, cmdID, options, inAddress, outAddress); |
| |
| if (inAddress != 0){ |
| COM.VariantClear(inAddress); |
| OS.GlobalFree(inAddress); |
| } |
| if (outAddress != 0) { |
| out.setData(outAddress); |
| COM.VariantClear(outAddress); |
| OS.GlobalFree(outAddress); |
| } |
| |
| return result; |
| } |
| IDispatch getAutomationObject() { |
| long /*int*/[] ppvObject = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIDispatch, ppvObject) != COM.S_OK) |
| return null; |
| return new IDispatch(ppvObject[0]); |
| } |
| protected GUID getClassID(String clientName) { |
| // create a GUID struct to hold the result |
| GUID guid = new GUID(); |
| |
| // create a null terminated array of char |
| char[] buffer = null; |
| if (clientName != null) { |
| int count = clientName.length(); |
| buffer = new char[count + 1]; |
| clientName.getChars(0, count, buffer, 0); |
| } |
| if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){ |
| int result = COM.CLSIDFromString(buffer, guid); |
| if (result != COM.S_OK) return null; |
| } |
| return guid; |
| } |
| private int GetContainer(long /*int*/ ppContainer) { |
| /* Simple containers that do not support links to their embedded |
| * objects probably do not need to implement this method. Instead, |
| * they can return E_NOINTERFACE and set ppContainer to NULL. |
| */ |
| if (ppContainer != 0) |
| OS.MoveMemory(ppContainer, new long /*int*/[]{0}, C.PTR_SIZEOF); |
| return COM.E_NOINTERFACE; |
| } |
| private SIZE getExtent() { |
| SIZE sizel = new SIZE(); |
| // get the current size of the embedded OLENatives object |
| if (objIOleObject != null) { |
| if ( objIViewObject2 != null && !COM.OleIsRunning(objIOleObject.getAddress())) { |
| objIViewObject2.GetExtent(aspect, -1, null, sizel); |
| } else { |
| objIOleObject.GetExtent(aspect, sizel); |
| } |
| } |
| return xFormHimetricToPixels(sizel); |
| } |
| /** |
| * Returns the indent value that would be used to compute the clipping area |
| * of the active X object. |
| * |
| * NOTE: The indent value is no longer being used by the client site. |
| * |
| * @return the rectangle representing the indent |
| */ |
| public Rectangle getIndent() { |
| return new Rectangle(indent.left, indent.right, indent.top, indent.bottom); |
| } |
| /** |
| * Returns the program ID of the OLE Document or ActiveX Control. |
| * |
| * @return the program ID of the OLE Document or ActiveX Control |
| */ |
| public String getProgramID(){ |
| return getProgID(appClsid); |
| } |
| String getProgID(GUID clsid) { |
| if (clsid != null){ |
| long /*int*/[] lplpszProgID = new long /*int*/[1]; |
| if (COM.ProgIDFromCLSID(clsid, lplpszProgID) == COM.S_OK) { |
| long /*int*/ hMem = lplpszProgID[0]; |
| int length = OS.GlobalSize(hMem); |
| long /*int*/ ptr = OS.GlobalLock(hMem); |
| char[] buffer = new char[length]; |
| OS.MoveMemory(buffer, ptr, length); |
| OS.GlobalUnlock(hMem); |
| OS.GlobalFree(hMem); |
| |
| String result = new String(buffer); |
| // remove null terminator |
| int index = result.indexOf("\0"); |
| return result.substring(0, index); |
| } |
| } |
| return null; |
| } |
| int ActivateMe(long /*int*/ pViewToActivate) { |
| if (pViewToActivate == 0) { |
| long /*int*/[] ppvObject = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIOleDocument, ppvObject) != COM.S_OK) return COM.E_FAIL; |
| IOleDocument objOleDocument = new IOleDocument(ppvObject[0]); |
| if (objOleDocument.CreateView(iOleInPlaceSite.getAddress(), 0, 0, ppvObject) != COM.S_OK) return COM.E_FAIL; |
| objOleDocument.Release(); |
| objDocumentView = new IOleDocumentView(ppvObject[0]); |
| } else { |
| objDocumentView = new IOleDocumentView(pViewToActivate); |
| objDocumentView.AddRef(); |
| objDocumentView.SetInPlaceSite(iOleInPlaceSite.getAddress()); |
| } |
| objDocumentView.UIActivate(1);//TRUE |
| RECT rect = getRect(); |
| objDocumentView.SetRect(rect); |
| objDocumentView.Show(1);//TRUE |
| return COM.S_OK; |
| } |
| protected int GetWindow(long /*int*/ phwnd) { |
| if (phwnd == 0) |
| return COM.E_INVALIDARG; |
| if (frame == null) { |
| OS.MoveMemory(phwnd, new long /*int*/[] {0}, C.PTR_SIZEOF); |
| return COM.E_NOTIMPL; |
| } |
| |
| // Copy the Window's handle into the memory passed in |
| OS.MoveMemory(phwnd, new long /*int*/[] {handle}, C.PTR_SIZEOF); |
| return COM.S_OK; |
| } |
| RECT getRect() { |
| Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels |
| RECT rect = new RECT(); |
| rect.left = area.x; |
| rect.top = area.y; |
| rect.right = area.x + area.width; |
| rect.bottom = area.y + area.height; |
| return rect; |
| } |
| private int GetWindowContext(long /*int*/ ppFrame, long /*int*/ ppDoc, long /*int*/ lprcPosRect, long /*int*/ lprcClipRect, long /*int*/ lpFrameInfo) { |
| if (frame == null || ppFrame == 0) |
| return COM.E_NOTIMPL; |
| |
| // fill in frame handle |
| long /*int*/ iOleInPlaceFrame = frame.getIOleInPlaceFrame(); |
| OS.MoveMemory(ppFrame, new long /*int*/[] {iOleInPlaceFrame}, C.PTR_SIZEOF); |
| frame.AddRef(); |
| |
| // null out document handle |
| if (ppDoc != 0) OS.MoveMemory(ppDoc, new long /*int*/[] {0}, C.PTR_SIZEOF); |
| |
| // fill in position and clipping info |
| RECT rect = getRect(); |
| if (lprcPosRect != 0) OS.MoveMemory(lprcPosRect, rect, RECT.sizeof); |
| if (lprcClipRect != 0) OS.MoveMemory(lprcClipRect, rect, RECT.sizeof); |
| |
| // get frame info |
| OLEINPLACEFRAMEINFO frameInfo = new OLEINPLACEFRAMEINFO(); |
| frameInfo.cb = OLEINPLACEFRAMEINFO.sizeof; |
| frameInfo.fMDIApp = 0; |
| frameInfo.hwndFrame = frame.handle; |
| Shell shell = getShell(); |
| Menu menubar = shell.getMenuBar(); |
| if (menubar != null && !menubar.isDisposed()) { |
| long /*int*/ hwnd = shell.handle; |
| int cAccel = (int)/*64*/OS.SendMessage(hwnd, OS.WM_APP, 0, 0); |
| if (cAccel != 0) { |
| long /*int*/ hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0); |
| if (hAccel != 0) { |
| frameInfo.cAccelEntries = cAccel; |
| frameInfo.haccel = hAccel; |
| } |
| } |
| } |
| COM.MoveMemory(lpFrameInfo, frameInfo, OLEINPLACEFRAMEINFO.sizeof); |
| |
| return COM.S_OK; |
| } |
| boolean isICAClient() { |
| return getProgramID().startsWith("Citrix.ICAClient"); //$NON-NLS-1$ |
| } |
| /** |
| * Returns whether ole document is dirty by checking whether the content |
| * of the file representing the document is dirty. |
| * |
| * @return <code>true</code> if the document has been modified, |
| * <code>false</code> otherwise. |
| * @since 3.1 |
| */ |
| public boolean isDirty() { |
| /* |
| * Note: this method must return true unless it is absolutely clear that the |
| * contents of the Ole Document do not differ from the contents in the file |
| * on the file system. |
| */ |
| |
| // Get access to the persistent storage mechanism |
| long /*int*/[] address = new long /*int*/[1]; |
| if (objIOleObject.QueryInterface(COM.IIDIPersistFile, address) != COM.S_OK) |
| return true; |
| IPersistFile permStorage = new IPersistFile(address[0]); |
| // Are the contents of the permanent storage different from the file? |
| int result = permStorage.IsDirty(); |
| permStorage.Release(); |
| if (result == COM.S_FALSE) return false; |
| return true; |
| } |
| @Override |
| public boolean isFocusControl () { |
| checkWidget (); |
| long /*int*/ focusHwnd = OS.GetFocus(); |
| if (objIOleInPlaceObject == null) return (handle == focusHwnd); |
| long /*int*/[] phwnd = new long /*int*/[1]; |
| objIOleInPlaceObject.GetWindow(phwnd); |
| while (focusHwnd != 0) { |
| if (phwnd[0] == focusHwnd) return true; |
| focusHwnd = OS.GetParent(focusHwnd); |
| } |
| return false; |
| } |
| private boolean isOffice2007(boolean program) { |
| String programID = getProgramID(); |
| if (programID == null) return false; |
| if (program) { |
| int lastDot = programID.lastIndexOf('.'); |
| if (lastDot != -1) { |
| programID = programID.substring(0, lastDot); |
| GUID guid = getClassID(programID); |
| programID = getProgID(guid); |
| if (programID == null) return false; |
| } |
| } |
| if (programID.equals("Word.Document.12")) return true; //$NON-NLS-1$ |
| if (programID.equals("Excel.Sheet.12")) return true; //$NON-NLS-1$ |
| if (programID.equals("PowerPoint.Show.12")) return true; //$NON-NLS-1$ |
| return false; |
| } |
| private int OnClose() { |
| return COM.S_OK; |
| } |
| private int OnDataChange(long /*int*/ pFormatetc, long /*int*/ pStgmed) { |
| return COM.S_OK; |
| } |
| private void onDispose(Event e) { |
| inDispose = true; |
| |
| // remove listeners |
| removeListener(SWT.Dispose, listener); |
| removeListener(SWT.FocusIn, listener); |
| removeListener(SWT.FocusOut, listener); |
| removeListener(SWT.Paint, listener); |
| removeListener(SWT.Traverse, listener); |
| removeListener(SWT.KeyDown, listener); |
| |
| if (state != STATE_NONE) |
| doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE); |
| deactivateInPlaceClient(); |
| releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame |
| deleteTempStorage(); |
| |
| frame.removeListener(SWT.Resize, listener); |
| frame.removeListener(SWT.Move, listener); |
| |
| frame.Release(); |
| frame = null; |
| } |
| void onFocusIn(Event e) { |
| if (inDispose) return; |
| if (state != STATE_UIACTIVE) { |
| long /*int*/[] ppvObject = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) { |
| IOleInPlaceObject objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]); |
| objIOleInPlaceObject.Release(); |
| doVerb(OLE.OLEIVERB_SHOW); |
| } |
| } |
| if (objIOleInPlaceObject == null) return; |
| if (isFocusControl()) return; |
| long /*int*/[] phwnd = new long /*int*/[1]; |
| objIOleInPlaceObject.GetWindow(phwnd); |
| if (phwnd[0] == 0) return; |
| OS.SetFocus(phwnd[0]); |
| } |
| void onFocusOut(Event e) { |
| } |
| private int OnInPlaceActivate() { |
| state = STATE_INPLACEACTIVE; |
| frame.setCurrentDocument(this); |
| if (objIOleObject == null) |
| return COM.S_OK; |
| long /*int*/[] ppvObject = new long /*int*/[1]; |
| if (objIOleObject.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) { |
| objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]); |
| } |
| return COM.S_OK; |
| } |
| private int OnInPlaceDeactivate() { |
| if (objIOleInPlaceObject != null) objIOleInPlaceObject.Release(); |
| objIOleInPlaceObject = null; |
| state = STATE_RUNNING; |
| redraw(); |
| Shell shell = getShell(); |
| if (isFocusControl() || frame.isFocusControl()) { |
| shell.traverse(SWT.TRAVERSE_TAB_NEXT); |
| } |
| return COM.S_OK; |
| } |
| private int OnPosRectChange(long /*int*/ lprcPosRect) { |
| Point size = DPIUtil.autoScaleUp(getSize()); // To Pixels |
| setExtent(size.x, size.y); |
| return COM.S_OK; |
| } |
| private void onPaint(Event e) { |
| if (state == STATE_RUNNING || state == STATE_INPLACEACTIVE) { |
| SIZE size = getExtent(); |
| Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels |
| RECT rect = new RECT(); |
| if (getProgramID().startsWith("Excel.Sheet")) { //$NON-NLS-1$ |
| rect.left = area.x; rect.right = area.x + (area.height * size.cx / size.cy); |
| rect.top = area.y; rect.bottom = area.y + area.height; |
| } else { |
| rect.left = area.x; rect.right = area.x + size.cx; |
| rect.top = area.y; rect.bottom = area.y + size.cy; |
| } |
| |
| long /*int*/ pArea = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, RECT.sizeof); |
| OS.MoveMemory(pArea, rect, RECT.sizeof); |
| COM.OleDraw(objIUnknown.getAddress(), aspect, e.gc.handle, pArea); |
| OS.GlobalFree(pArea); |
| } |
| } |
| private void onResize(Event e) { |
| setBounds(); |
| } |
| private void OnSave() { |
| } |
| private int OnShowWindow(int fShow) { |
| return COM.S_OK; |
| } |
| private int OnUIActivate() { |
| if (objIOleInPlaceObject == null) return COM.E_FAIL; |
| state = STATE_UIACTIVE; |
| long /*int*/[] phwnd = new long /*int*/[1]; |
| if (objIOleInPlaceObject.GetWindow(phwnd) == COM.S_OK) { |
| OS.SetWindowPos(phwnd[0], OS.HWND_TOP, 0, 0, 0, 0, OS.SWP_NOSIZE | OS.SWP_NOMOVE); |
| } |
| return COM.S_OK; |
| } |
| int OnUIDeactivate(int fUndoable) { |
| // currently, we are ignoring the fUndoable flag |
| if (frame == null || frame.isDisposed()) return COM.S_OK; |
| state = STATE_INPLACEACTIVE; |
| frame.SetActiveObject(0,0); |
| redraw(); |
| Shell shell = getShell(); |
| if (isFocusControl() || frame.isFocusControl()) { |
| shell.traverse(SWT.TRAVERSE_TAB_NEXT); |
| } |
| Menu menubar = shell.getMenuBar(); |
| if (menubar == null || menubar.isDisposed()) |
| return COM.S_OK; |
| |
| long /*int*/ shellHandle = shell.handle; |
| OS.SetMenu(shellHandle, menubar.handle); |
| return COM.OleSetMenuDescriptor(0, shellHandle, 0, 0, 0); |
| } |
| private void onTraverse(Event event) { |
| switch (event.detail) { |
| case SWT.TRAVERSE_ESCAPE: |
| case SWT.TRAVERSE_RETURN: |
| case SWT.TRAVERSE_TAB_NEXT: |
| case SWT.TRAVERSE_TAB_PREVIOUS: |
| case SWT.TRAVERSE_PAGE_NEXT: |
| case SWT.TRAVERSE_PAGE_PREVIOUS: |
| case SWT.TRAVERSE_MNEMONIC: |
| event.doit = true; |
| break; |
| } |
| } |
| private int OnViewChange(int dwAspect, int lindex) { |
| return COM.S_OK; |
| } |
| protected int QueryInterface(long /*int*/ riid, long /*int*/ ppvObject) { |
| |
| if (riid == 0 || ppvObject == 0) |
| return COM.E_NOINTERFACE; |
| GUID guid = new GUID(); |
| COM.MoveMemory(guid, riid, GUID.sizeof); |
| |
| if (COM.IsEqualGUID(guid, COM.IIDIUnknown)) { |
| OS.MoveMemory(ppvObject, new long /*int*/[] {iUnknown.getAddress()}, C.PTR_SIZEOF); |
| AddRef(); |
| return COM.S_OK; |
| } |
| if (COM.IsEqualGUID(guid, COM.IIDIAdviseSink)) { |
| OS.MoveMemory(ppvObject, new long /*int*/[] {iAdviseSink.getAddress()}, C.PTR_SIZEOF); |
| AddRef(); |
| return COM.S_OK; |
| } |
| if (COM.IsEqualGUID(guid, COM.IIDIOleClientSite)) { |
| OS.MoveMemory(ppvObject, new long /*int*/[] {iOleClientSite.getAddress()}, C.PTR_SIZEOF); |
| AddRef(); |
| return COM.S_OK; |
| } |
| if (COM.IsEqualGUID(guid, COM.IIDIOleInPlaceSite)) { |
| OS.MoveMemory(ppvObject, new long /*int*/[] {iOleInPlaceSite.getAddress()}, C.PTR_SIZEOF); |
| AddRef(); |
| return COM.S_OK; |
| } |
| if (COM.IsEqualGUID(guid, COM.IIDIOleDocumentSite )) { |
| String progID = getProgramID(); |
| if (!progID.startsWith("PowerPoint")) { //$NON-NLS-1$ |
| OS.MoveMemory(ppvObject, new long /*int*/[] {iOleDocumentSite.getAddress()}, C.PTR_SIZEOF); |
| AddRef(); |
| return COM.S_OK; |
| } |
| } |
| OS.MoveMemory(ppvObject, new long /*int*/[] {0}, C.PTR_SIZEOF); |
| return COM.E_NOINTERFACE; |
| } |
| /** |
| * Returns the status of the specified command. The status is any bitwise OR'd combination of |
| * SWTOLE.OLECMDF_SUPPORTED, SWTOLE.OLECMDF_ENABLED, SWTOLE.OLECMDF_LATCHED, SWTOLE.OLECMDF_NINCHED. |
| * You can query the status of a command before invoking it with OleClientSite.exec. The |
| * OLE Document or ActiveX Control must support the IOleCommandTarget to make use of this method. |
| * |
| * @param cmd the ID of a command; these are the OLE.OLECMDID_ values - a small set of common |
| * commands |
| * |
| * @return the status of the specified command or 0 if unable to query the OLE Object; these are the |
| * OLE.OLECMDF_ values |
| */ |
| public int queryStatus(int cmd) { |
| |
| if (objIOleCommandTarget == null) { |
| long /*int*/[] address = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK) |
| return 0; |
| objIOleCommandTarget = new IOleCommandTarget(address[0]); |
| } |
| |
| OLECMD olecmd = new OLECMD(); |
| olecmd.cmdID = cmd; |
| |
| int result = objIOleCommandTarget.QueryStatus(null, 1, olecmd, null); |
| |
| if (result != COM.S_OK) return 0; |
| |
| return olecmd.cmdf; |
| } |
| protected int Release() { |
| refCount--; |
| |
| if (refCount == 0) { |
| disposeCOMInterfaces(); |
| } |
| return refCount; |
| } |
| protected void releaseObjectInterfaces() { |
| |
| if (objIOleInPlaceObject!= null) |
| objIOleInPlaceObject.Release(); |
| objIOleInPlaceObject = null; |
| |
| if (objIOleObject != null) { |
| objIOleObject.Close(COM.OLECLOSE_NOSAVE); |
| objIOleObject.Release(); |
| } |
| objIOleObject = null; |
| |
| if (objDocumentView != null){ |
| objDocumentView.Release(); |
| } |
| objDocumentView = null; |
| |
| if (objIViewObject2 != null) { |
| objIViewObject2.SetAdvise(aspect, 0, 0); |
| objIViewObject2.Release(); |
| } |
| objIViewObject2 = null; |
| |
| if (objIOleCommandTarget != null) |
| objIOleCommandTarget.Release(); |
| objIOleCommandTarget = null; |
| |
| if (objIUnknown != null){ |
| objIUnknown.Release(); |
| } |
| objIUnknown = null; |
| |
| if (COM.FreeUnusedLibraries) { |
| COM.CoFreeUnusedLibraries(); |
| } |
| } |
| /** |
| * Saves the document to the specified file and includes OLE specific information if specified. |
| * This method must <b>only</b> be used for files that have an OLE Storage format. For example, |
| * a word file edited with Word.Document should be saved using this method because there is |
| * formating information that should be stored in the OLE specific Storage format. |
| * |
| * @param file the file to which the changes are to be saved |
| * @param includeOleInfo the flag to indicate whether OLE specific information should be saved. |
| * |
| * @return true if the save was successful |
| */ |
| public boolean save(File file, boolean includeOleInfo) { |
| /* |
| * Bug in Office 2007. Saving Office 2007 documents to compound file storage object |
| * causes the output file to be corrupted. The fix is to detect Office 2007 documents |
| * using the program ID and save only the content of the 'Package' stream. |
| */ |
| if (isOffice2007(false)) { |
| return saveOffice2007(file); |
| } |
| if (includeOleInfo) |
| return saveToStorageFile(file); |
| return saveToTraditionalFile(file); |
| } |
| private boolean saveFromContents(long /*int*/ address, File file) { |
| |
| boolean success = false; |
| |
| IStream tempContents = new IStream(address); |
| tempContents.AddRef(); |
| |
| try { |
| FileOutputStream writer = new FileOutputStream(file); |
| |
| int increment = 1024 * 4; |
| long /*int*/ pv = OS.CoTaskMemAlloc(increment); |
| int[] pcbWritten = new int[1]; |
| while (tempContents.Read(pv, increment, pcbWritten) == COM.S_OK && pcbWritten[0] > 0) { |
| byte[] buffer = new byte[ pcbWritten[0]]; |
| OS.MoveMemory(buffer, pv, pcbWritten[0]); |
| writer.write(buffer); // Note: if file does not exist, this will create the file the |
| // first time it is called |
| success = true; |
| } |
| OS.CoTaskMemFree(pv); |
| |
| writer.close(); |
| |
| } catch (IOException err) { |
| } |
| |
| tempContents.Release(); |
| |
| return success; |
| } |
| private boolean saveFromOle10Native(long /*int*/ address, File file) { |
| |
| boolean success = false; |
| |
| IStream tempContents = new IStream(address); |
| tempContents.AddRef(); |
| |
| // The "\1Ole10Native" stream contains a DWORD header whose value is the length |
| // of the native data that follows. |
| long /*int*/ pv = OS.CoTaskMemAlloc(4); |
| int[] size = new int[1]; |
| int rc = tempContents.Read(pv, 4, null); |
| OS.MoveMemory(size, pv, 4); |
| OS.CoTaskMemFree(pv); |
| if (rc == COM.S_OK && size[0] > 0) { |
| |
| // Read the data |
| byte[] buffer = new byte[size[0]]; |
| pv = OS.CoTaskMemAlloc(size[0]); |
| rc = tempContents.Read(pv, size[0], null); |
| OS.MoveMemory(buffer, pv, size[0]); |
| OS.CoTaskMemFree(pv); |
| |
| // open the file and write data into it |
| try { |
| FileOutputStream writer = new FileOutputStream(file); |
| writer.write(buffer); // Note: if file does not exist, this will create the file |
| writer.close(); |
| |
| success = true; |
| } catch (IOException err) { |
| } |
| } |
| tempContents.Release(); |
| |
| return success; |
| } |
| private int SaveObject() { |
| |
| updateStorage(); |
| |
| return COM.S_OK; |
| } |
| private boolean saveOffice2007(File file) { |
| if (file == null || file.isDirectory()) return false; |
| if (!updateStorage()) return false; |
| boolean result = false; |
| |
| /* Excel fails to open the package stream when the PersistStorage is not in hands off mode */ |
| long /*int*/[] ppv = new long /*int*/[1]; |
| IPersistStorage iPersistStorage = null; |
| if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) == COM.S_OK) { |
| iPersistStorage = new IPersistStorage(ppv[0]); |
| tempStorage.AddRef(); |
| iPersistStorage.HandsOffStorage(); |
| } |
| long /*int*/[] address = new long /*int*/[1]; |
| int grfMode = COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE; |
| if (tempStorage.OpenStream("Package", 0, grfMode, 0, address) == COM.S_OK) { //$NON-NLS-1$ |
| result = saveFromContents(address[0], file); |
| } |
| if (iPersistStorage != null) { |
| iPersistStorage.SaveCompleted(tempStorage.getAddress()); |
| tempStorage.Release(); |
| iPersistStorage.Release(); |
| } |
| return result; |
| } |
| /** |
| * Saves the document to the specified file and includes OLE specific information. This method |
| * must <b>only</b> be used for files that have an OLE Storage format. For example, a word file |
| * edited with Word.Document should be saved using this method because there is formating information |
| * that should be stored in the OLE specific Storage format. |
| * |
| * @param file the file to which the changes are to be saved |
| * |
| * @return true if the save was successful |
| */ |
| private boolean saveToStorageFile(File file) { |
| // The file will be saved using the formating of the current application - this |
| // may not be the format of the application that was originally used to create the file |
| // e.g. if an Excel file is opened in Word, the Word application will save the file in the |
| // Word format |
| // Note: if the file already exists, some applications will not overwrite the file |
| // In these cases, you should delete the file first (probably save the contents of the file in case the |
| // save fails) |
| if (file == null || file.isDirectory()) return false; |
| if (!updateStorage()) return false; |
| |
| // get access to the persistent storage mechanism |
| long /*int*/[] address = new long /*int*/[1]; |
| if (objIOleObject.QueryInterface(COM.IIDIPersistStorage, address) != COM.S_OK) return false; |
| IPersistStorage permStorage = new IPersistStorage(address[0]); |
| try { |
| address = new long /*int*/[1]; |
| char[] path = (file.getAbsolutePath()+"\0").toCharArray(); |
| int mode = COM.STGM_TRANSACTED | COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE; |
| int result = COM.StgCreateDocfile(path, mode, 0, address); //Does an AddRef if successful |
| if (result != COM.S_OK) return false; |
| IStorage storage = new IStorage(address[0]); |
| try { |
| if (COM.OleSave(permStorage.getAddress(), storage.getAddress(), false) == COM.S_OK) { |
| if (storage.Commit(COM.STGC_DEFAULT) == COM.S_OK) { |
| return true; |
| } |
| } |
| } finally { |
| storage.Release(); |
| } |
| } finally { |
| permStorage.Release(); |
| } |
| return false; |
| } |
| /** |
| * Saves the document to the specified file. This method must be used for |
| * files that do not have an OLE Storage format. For example, a bitmap file edited with MSPaint |
| * should be saved using this method because bitmap is a standard format that does not include any |
| * OLE specific data. |
| * |
| * @param file the file to which the changes are to be saved |
| * |
| * @return true if the save was successful |
| */ |
| private boolean saveToTraditionalFile(File file) { |
| // Note: if the file already exists, some applications will not overwrite the file |
| // In these cases, you should delete the file first (probably save the contents of the file in case the |
| // save fails) |
| if (file == null || file.isDirectory()) |
| return false; |
| if (!updateStorage()) |
| return false; |
| |
| long /*int*/[] address = new long /*int*/[1]; |
| // Look for a CONTENTS stream |
| if (tempStorage.OpenStream("CONTENTS", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$ |
| return saveFromContents(address[0], file); |
| |
| // Look for Ole 1.0 object stream |
| if (tempStorage.OpenStream("\1Ole10Native", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$ |
| return saveFromOle10Native(address[0], file); |
| |
| return false; |
| } |
| private int Scroll_64(long /*int*/ scrollExtent) { |
| return COM.S_OK; |
| } |
| private int Scroll(int scrollExtent_cx, int scrollExtent_cy) { |
| return COM.S_OK; |
| } |
| void setBorderSpace(RECT newBorderwidth) { |
| borderWidths = newBorderwidth; |
| // readjust size and location of client site |
| setBounds(); |
| } |
| void setBounds() { |
| Rectangle area = DPIUtil.autoScaleUp(frame.getClientArea()); // To Pixels |
| setBounds(DPIUtil.autoScaleDown(borderWidths.left), |
| DPIUtil.autoScaleDown(borderWidths.top), |
| DPIUtil.autoScaleDown(area.width - borderWidths.left - borderWidths.right), |
| DPIUtil.autoScaleDown(area.height - borderWidths.top - borderWidths.bottom)); |
| setObjectRects(); |
| } |
| private void setExtent(int width, int height){ |
| // Resize the width and height of the embedded/linked OLENatives object |
| // to the specified values. |
| |
| if (objIOleObject == null || isStatic || inUpdate) return; |
| SIZE currentExtent = getExtent(); |
| if (width == currentExtent.cx && height == currentExtent.cy) return; |
| |
| SIZE newExtent = new SIZE(); |
| newExtent.cx = width; newExtent.cy = height; |
| newExtent = xFormPixelsToHimetric(newExtent); |
| |
| // Get the server running first, then do a SetExtent, then show it |
| boolean alreadyRunning = COM.OleIsRunning(objIOleObject.getAddress()); |
| if (!alreadyRunning) |
| COM.OleRun(objIOleObject.getAddress()); |
| |
| if (objIOleObject.SetExtent(aspect, newExtent) == COM.S_OK){ |
| inUpdate = true; |
| objIOleObject.Update(); |
| inUpdate = false; |
| if (!alreadyRunning) |
| // Close server if it wasn't already running upon entering this method. |
| objIOleObject.Close(COM.OLECLOSE_SAVEIFDIRTY); |
| } |
| } |
| /** |
| * The indent value is no longer being used by the client site. |
| * |
| * @param newIndent the rectangle representing the indent amount |
| */ |
| public void setIndent(Rectangle newIndent) { |
| indent = new RECT(); |
| indent.left = newIndent.x; |
| indent.right = newIndent.width; |
| indent.top = newIndent.y; |
| indent.bottom = newIndent.height; |
| } |
| private void setObjectRects() { |
| if (objIOleInPlaceObject == null) return; |
| // size the object to fill the available space |
| // leave a border |
| RECT rect = getRect(); |
| objIOleInPlaceObject.SetObjectRects(rect, rect); |
| } |
| |
| private int ShowObject() { |
| /* Tells the container to position the object so it is visible to |
| * the user. This method ensures that the container itself is |
| * visible and not minimized. |
| */ |
| setBounds(); |
| return COM.S_OK; |
| } |
| /** |
| * Displays a dialog with the property information for this OLE Object. The OLE Document or |
| * ActiveX Control must support the ISpecifyPropertyPages interface. |
| * |
| * @param title the name that will appear in the titlebar of the dialog |
| */ |
| public void showProperties(String title) { |
| |
| // Get the Property Page information from the OLE Object |
| long /*int*/[] ppvObject = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDISpecifyPropertyPages, ppvObject) != COM.S_OK) return; |
| ISpecifyPropertyPages objISPP = new ISpecifyPropertyPages(ppvObject[0]); |
| CAUUID caGUID = new CAUUID(); |
| int result = objISPP.GetPages(caGUID); |
| objISPP.Release(); |
| if (result != COM.S_OK) return; |
| |
| // create a frame in which to display the pages |
| char[] chTitle = null; |
| if (title != null) { |
| chTitle = new char[title.length()]; |
| title.getChars(0, title.length(), chTitle, 0); |
| } |
| result = COM.OleCreatePropertyFrame(frame.handle, 10, 10, chTitle, 1, new long /*int*/[] {objIUnknown.getAddress()}, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, 0); |
| |
| // free the property page information |
| OS.CoTaskMemFree(caGUID.pElems); |
| } |
| private boolean updateStorage() { |
| |
| if (tempStorage == null) return false; |
| |
| long /*int*/[] ppv = new long /*int*/[1]; |
| if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) != COM.S_OK) return false; |
| IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]); |
| |
| int result = COM.OleSave(iPersistStorage.getAddress(), tempStorage.getAddress(), true); |
| |
| if (result != COM.S_OK){ |
| // OleSave will fail for static objects, so do what OleSave does. |
| COM.WriteClassStg(tempStorage.getAddress(), objClsid); |
| result = iPersistStorage.Save(tempStorage.getAddress(), true); |
| } |
| |
| tempStorage.Commit(COM.STGC_DEFAULT); |
| result = iPersistStorage.SaveCompleted(0); |
| iPersistStorage.Release(); |
| |
| return true; |
| } |
| private SIZE xFormHimetricToPixels(SIZE aSize) { |
| // Return a new Size which is the pixel transformation of a |
| // size in HIMETRIC units. |
| |
| long /*int*/ hDC = OS.GetDC(0); |
| int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x |
| int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y |
| OS.ReleaseDC(0, hDC); |
| int cx = Compatibility.round(aSize.cx * xppi, 2540); // 2540 HIMETRIC units per inch |
| int cy = Compatibility.round(aSize.cy * yppi, 2540); |
| SIZE size = new SIZE(); |
| size.cx = cx; |
| size.cy = cy; |
| return size; |
| } |
| private SIZE xFormPixelsToHimetric(SIZE aSize) { |
| // Return a new size which is the HIMETRIC transformation of a |
| // size in pixel units. |
| |
| long /*int*/ hDC = OS.GetDC(0); |
| int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x |
| int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y |
| OS.ReleaseDC(0, hDC); |
| int cx = Compatibility.round(aSize.cx * 2540, xppi); // 2540 HIMETRIC units per inch |
| int cy = Compatibility.round(aSize.cy * 2540, yppi); |
| SIZE size = new SIZE(); |
| size.cx = cx; |
| size.cy = cy; |
| return size; |
| } |
| } |