org.eclipse.swt.ole.win32.OleClientSite.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.swt.ole.win32.OleClientSite.java

Source

/*******************************************************************************
 * 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.*;

/**
 * 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>
 * <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
    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[] 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]);

            // 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[] address = new long[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[] address = new long[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[] address = new long[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[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 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[] ppv = new long[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[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[] ppvObject = new long[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[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[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[] ppvClientSite = new long[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[1];
        if (objIUnknown.QueryInterface(COM.IIDIOleLink, ppvObject) == COM.S_OK) {
            IOleLink objIOleLink = new IOleLink(ppvObject[0]);
            long[] ppmk = new long[1];
            if (objIOleLink.GetSourceMoniker(ppmk) == COM.S_OK) {
                new IUnknown(ppmk[0]).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() {

        iOleClientSite = new COMObject(new int[] { 2, 0, 0, 0, 3, 1, 0, 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 SaveObject();
            }

            // method4 GetMoniker - not implemented
            @Override
            public long method5(long[] args) {
                return GetContainer(args[0]);
            }

            @Override
            public long method6(long[] args) {
                return ShowObject();
            }

            @Override
            public long method7(long[] args) {
                return OnShowWindow((int) args[0]);
            }
            // method8 RequestNewObjectLayout - not implemented
        };

        iAdviseSink = new COMObject(new int[] { 2, 0, 0, 2, 2, 1, 0, 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 OnDataChange(args[0], args[1]);
            }

            @Override
            public long method4(long[] args) {
                return OnViewChange((int) args[0], (int) args[1]);
            }

            //method5 OnRename - not implemented
            @Override
            public long method6(long[] args) {
                OnSave();
                return 0;
            }

            @Override
            public long method7(long[] args) {
                return OnClose();
            }
        };

        iOleInPlaceSite = new COMObject(new int[] { 2, 0, 0, 1, 1, 0, 0, 0, 5, 1, 1, 0, 0, 0, 1 }) {
            @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 GetWindow(args[0]);
            }

            @Override
            public long method4(long[] args) {
                return ContextSensitiveHelp((int) args[0]);
            }

            @Override
            public long method5(long[] args) {
                return CanInPlaceActivate();
            }

            @Override
            public long method6(long[] args) {
                return OnInPlaceActivate();
            }

            @Override
            public long method7(long[] args) {
                return OnUIActivate();
            }

            @Override
            public long method8(long[] args) {
                return GetWindowContext(args[0], args[1], args[2], args[3], args[4]);
            }

            @Override
            public long method9(long[] args) {
                return Scroll(args[0]);
            }

            @Override
            public long method10(long[] args) {
                return OnUIDeactivate((int) args[0]);
            }

            @Override
            public long method11(long[] args) {
                return OnInPlaceDeactivate();
            }

            // method12 DiscardUndoState - not implemented
            // method13 DeactivateAndUndoChange - not implemented
            @Override
            public long method14(long[] args) {
                return OnPosRectChange(args[0]);
            }
        };

        iOleDocumentSite = new COMObject(new int[] { 2, 0, 0, 1 }) {
            @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 ActivateMe(args[0]);
            }
        };
    }

    protected IStorage createTempStorage() {
        long[] tempStorage = new long[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 (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[] address = new long[1];
            if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
                return OLE.ERROR_INTERFACE_NOT_FOUND;
            objIOleCommandTarget = new IOleCommandTarget(address[0]);
        }

        long inAddress = 0;
        if (in != null) {
            inAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
            in.getData(inAddress);
        }
        long 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[] ppvObject = new long[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 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[] { 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, 0, 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[] lplpszProgID = new long[1];
            if (COM.ProgIDFromCLSID(clsid, lplpszProgID) == COM.S_OK) {
                long hMem = lplpszProgID[0];
                int length = OS.GlobalSize(hMem);
                long 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 pViewToActivate) {
        if (pViewToActivate == 0) {
            long[] ppvObject = new long[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 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;
    }

    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 ppFrame, long ppDoc, long lprcPosRect, long lprcClipRect, long lpFrameInfo) {
        if (frame == null || ppFrame == 0)
            return COM.E_NOTIMPL;

        // fill in frame handle
        long iOleInPlaceFrame = frame.getIOleInPlaceFrame();
        OS.MoveMemory(ppFrame, new long[] { iOleInPlaceFrame }, C.PTR_SIZEOF);
        frame.AddRef();

        // null out document handle
        if (ppDoc != 0)
            OS.MoveMemory(ppDoc, new long[] { 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 hwnd = shell.handle;
            int cAccel = (int) OS.SendMessage(hwnd, OS.WM_APP, 0, 0);
            if (cAccel != 0) {
                long 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[] address = new long[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 focusHwnd = OS.GetFocus();
        if (objIOleInPlaceObject == null)
            return (handle == focusHwnd);
        long[] phwnd = new long[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")) //$NON-NLS-1$
            return true;
        if (programID.equals("Excel.Sheet.12")) //$NON-NLS-1$
            return true;
        if (programID.equals("PowerPoint.Show.12")) //$NON-NLS-1$
            return true;
        return false;
    }

    private int OnClose() {
        return COM.S_OK;
    }

    private int OnDataChange(long pFormatetc, long 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[] ppvObject = new long[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[] phwnd = new long[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[] ppvObject = new long[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 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 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[] phwnd = new long[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 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 riid, long 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) || COM.IsEqualGUID(guid, COM.IIDIOleClientSite)) {
            OS.MoveMemory(ppvObject, new long[] { iOleClientSite.getAddress() }, C.PTR_SIZEOF);
            AddRef();
            return COM.S_OK;
        }
        if (COM.IsEqualGUID(guid, COM.IIDIAdviseSink)) {
            OS.MoveMemory(ppvObject, new long[] { iAdviseSink.getAddress() }, C.PTR_SIZEOF);
            AddRef();
            return COM.S_OK;
        }
        if (COM.IsEqualGUID(guid, COM.IIDIOleInPlaceSite)) {
            OS.MoveMemory(ppvObject, new long[] { 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[] { iOleDocumentSite.getAddress() }, C.PTR_SIZEOF);
                AddRef();
                return COM.S_OK;
            }
        }
        OS.MoveMemory(ppvObject, new long[] { 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[] address = new long[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, 0);

        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 address, File file) {

        boolean success = false;

        IStream tempContents = new IStream(address);
        tempContents.AddRef();

        try {
            FileOutputStream writer = new FileOutputStream(file);

            int increment = 1024 * 4;
            long 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 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 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[] ppv = new long[1];
        IPersistStorage iPersistStorage = null;
        if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) == COM.S_OK) {
            iPersistStorage = new IPersistStorage(ppv[0]);
            tempStorage.AddRef();
            iPersistStorage.HandsOffStorage();
        }
        long[] address = new long[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[] address = new long[1];
        if (objIOleObject.QueryInterface(COM.IIDIPersistStorage, address) != COM.S_OK)
            return false;
        IPersistStorage permStorage = new IPersistStorage(address[0]);
        try {
            address = new long[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[] address = new long[1];
        // Look for a CONTENTS stream
        if (tempStorage.OpenStream("CONTENTS", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, //$NON-NLS-1$
                address) == COM.S_OK)
            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, //$NON-NLS-1$
                0, address) == COM.S_OK)
            return saveFromOle10Native(address[0], file);

        return false;
    }

    private int Scroll(long scrollExtent) {
        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[] ppvObject = new long[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[] { 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[] ppv = new long[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 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 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;
    }
}