blob: ad36e69e01b056a06800ad3af620fd9c86015a33 [file] [log] [blame]
package org.eclipse.swt.ole.win32;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.Compatibility;
import org.eclipse.swt.internal.ole.win32.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.internal.win32.*;
/**
* 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>
*
*/
public class OleClientSite extends Composite {
// Interfaces for this Ole Client Container
private COMObject iUnknown;
private COMObject iOleClientSite;
private COMObject iAdviseSink;
private COMObject iOleInPlaceSite;
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;
// Related storage information
protected IStorage tempStorage; // IStorage interface of the receiver
// Internal state and style information
private boolean active; // Track whether the object is in place active
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.
private RECT borderWidths = new RECT();
private RECT indent = new RECT();
private boolean inUpdate = false;
private boolean inInit = true;
private static final String WORDPROGID = "Word.Document";
private Listener listener;
protected OleClientSite(Composite parent, int style) {
// 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 (true) {
if (parent instanceof OleFrame){
frame = (OleFrame)parent;
break;
}
parent = parent.getParent();
if (parent == null) break;
}
if (frame == null) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
frame.AddRef();
active = false;
aspect = COM.DVASPECT_CONTENT;
type = COM.OLEEMBEDDED;
isStatic = false;
listener = new Listener() {
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:
onFocusIn(e);
break;
case SWT.Paint:
onPaint(e);
break;
case SWT.Traverse:
onTraverse(e);
break;
case SWT.KeyDown:
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.Paint, listener);
addListener(SWT.Traverse, listener);
addListener(SWT.KeyDown, 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 SWTError
* <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
* <li>ERROR_ERROR_NULL_ARGUMENT when the parent is null</ul>
* @exception SWTError
* <ul><li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
* <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
* <li>ERROR_CANNOT_OPEN_FILE when failed to open file
* <li>ERROR_INTERFACES_NOT_INITIALIZED when unable to create callbacks for OLE Interfaces</ul>
*
*/
public OleClientSite(Composite parent, int style, File file) {
this(parent, style);
try {
if (file == null || file.isDirectory() || !file.exists())
OLE.error(OLE.ERROR_INVALID_ARGUMENT);
// Is there an associated CLSID?
appClsid = new GUID();
char[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
int result = COM.GetClassFile(fileName, appClsid);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
// Open a temporary storage object
tempStorage = createTempStorage();
// Create ole object with storage object
int[] address = new int[1];
result = COM.OleCreateFromFile(appClsid, fileName, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, 0, tempStorage.getAddress(), address);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
objIUnknown = new IUnknown(address[0]);
// Init sinks
addObjectReferences();
COM.OleRun(objIUnknown.getAddress());
} catch (SWTException e) {
disposeCOMInterfaces();
frame.Release();
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 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)
*
* @exception SWTError
* <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
* <li>ERROR_ERROR_NULL_ARGUMENT when the parent is null
* <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
* <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
* <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
* <li>ERROR_INTERFACES_NOT_INITIALIZED when unable to create callbacks for OLE Interfaces</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
int[] address = new int[1];
int result = COM.OleCreate(appClsid, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, 0, tempStorage.getAddress(), address);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
objIUnknown = new IUnknown(address[0]);
// Init sinks
addObjectReferences();
COM.OleRun(objIUnknown.getAddress());
} catch (SWTException e) {
disposeCOMInterfaces();
frame.Release();
throw e;
}
}
/**
* @private
*
* 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.
*
* @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 SWTError
* <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
* <li>ERROR_ERROR_NULL_ARGUMENT when the parent is null
* <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
* <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
* <li>ERROR_INTERFACES_NOT_INITIALIZED when unable to create callbacks for OLE Interfaces</ul>
*
*/
public OleClientSite(Composite parent, int style, String progId, File file) {
this(parent, style);
try {
if (file == null || file.isDirectory() || !file.exists())
OLE.error(OLE.ERROR_INVALID_ARGUMENT);
appClsid = getClassID(progId);
// Are we opening this file with the preferred OLE object?
char[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
GUID fileClsid = new GUID();
COM.GetClassFile(fileName, fileClsid);
if (COM.IsEqualGUID(appClsid, fileClsid)){
// use default mechanism
// Open a temporary storage object
tempStorage = createTempStorage();
// Create ole object with storage object
int[] address = new int[1];
int result = COM.OleCreateFromFile(appClsid, fileName, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, 0, tempStorage.getAddress(), address);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
objIUnknown = new IUnknown(address[0]);
} else {
// use a conversion mechanism
// Word does not follow the standard and does not use "CONTENTS" as the name of
// its primary stream
String contentStream = "CONTENTS";
GUID wordGUID = getClassID(WORDPROGID);
if (COM.IsEqualGUID(appClsid, wordGUID)) contentStream = "WordDocument";
// Copy over the contents of the file into a new temporary storage object
OleFile oleFile = new OleFile(file, contentStream, OleFile.READ);
IStorage storage = oleFile.getRootStorage();
storage.AddRef();
// 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);
oleFile.dispose();
// create ole client
int[] ppv = new int[1];
result = COM.CoCreateInstance(appClsid, 0, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, COM.IIDIUnknown, ppv);
if (result != COM.S_OK){
tempStorage.Release();
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
}
objIUnknown = new IUnknown(ppv[0]);
// get the persistant storage of the ole client
ppv = new int[1];
result = objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv);
if (result != COM.S_OK){
tempStorage.Release();
objIUnknown.Release();
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){
tempStorage.Release();
tempStorage = null;
objIUnknown.Release();
objIUnknown = null;
OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
}
}
// Init sinks
addObjectReferences();
COM.OleRun(objIUnknown.getAddress());
} catch (SWTException e) {
disposeCOMInterfaces();
frame.Release();
throw e;
}
}
private void activateInPlaceClient() {
if (objIOleInPlaceObject == null) return;
// bring client window to foreground
int[] phwnd = new 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);
}
frame.setCurrentDocument(this);
}
protected void addObjectReferences() {
//
int[] ppvObject = new 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 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 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]);
objIOleObject.SetClientSite(iOleClientSite.getAddress());
int[] pdwConnection = new int[1];
objIOleObject.Advise(iAdviseSink.getAddress(), pdwConnection);
objIOleObject.SetHostNames("main", "main");
// 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 int[1];
if (objIUnknown.QueryInterface(COM.IIDIOleLink, ppvObject) == COM.S_OK) {
IOleLink objIOleLink = new IOleLink(ppvObject[0]);
int[] ppmk = new 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}){
public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
public int method1(int[] args) {return AddRef();}
public int method2(int[] args) {return Release();}
};
iOleClientSite = new COMObject(new int[]{2, 0, 0, 0, 3, 1, 0, 1, 0}){
public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
public int method1(int[] args) {return AddRef();}
public int method2(int[] args) {return Release();}
public int method3(int[] args) {return SaveObject();}
// method4 GetMoniker - not implemented
public int method5(int[] args) {return GetContainer(args[0]);}
public int method6(int[] args) {return ShowObject();}
public int method7(int[] args) {return OnShowWindow(args[0]);}
// method8 RequestNewObjectLayout - not implemented
};
iAdviseSink = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 0, 0}){
public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
public int method1(int[] args) {return AddRef();}
public int method2(int[] args) {return Release();}
public int method3(int[] args) {return OnDataChange(args[0], args[1]);}
public int method4(int[] args) {return OnViewChange(args[0], args[1]);}
//method5 OnRename - not implemented
public int method6(int[] args) {OnSave();return 0;}
public int method7(int[] args) {return OnClose();}
};
iOleInPlaceSite = new COMObject(new int[]{2, 0, 0, 1, 1, 0, 0, 0, 5, 1, 1, 0, 0, 0, 1}){
public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
public int method1(int[] args) {return AddRef();}
public int method2(int[] args) {return Release();}
public int method3(int[] args) {return GetWindow(args[0]);}
public int method4(int[] args) {return ContextSensitiveHelp(args[0]);}
public int method5(int[] args) {return CanInPlaceActivate();}
public int method6(int[] args) {return OnInPlaceActivate();}
public int method7(int[] args) {return OnUIActivate();}
public int method8(int[] args) {return GetWindowContext(args[0], args[1], args[2], args[3], args[4]);}
public int method9(int[] args) {return Scroll(args[0]);}
public int method10(int[] args) {return OnUIDeactivate(args[0]);}
public int method11(int[] args) {return OnInPlaceDeactivate();}
// method12 DiscardUndoState - not implemented
// method13 DeactivateAndUndoChange - not implemented
public int method14(int[] args) {return OnPosRectChange(args[0]);}
};
}
protected IStorage createTempStorage() {
int[] tempStorage = new 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 (active && 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;
}
/**
* 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) {
if (objIOleObject == null || isStatic)
return COM.E_FAIL;
boolean wasActive = active;
int oleobject = objIOleObject.getAddress();
COM.OleRun(oleobject);
// See PR: 1FV9RZW
int result = objIOleObject.DoVerb(verb, null, iOleClientSite.getAddress(), 0, handle, null);
if (active) setObjectRects();
// synch up with state of object
if (wasActive != active){
if (active) {
activateInPlaceClient();
} else {
deactivateInPlaceClient();
}
}
if (active && 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) {
int[] address = new int[1];
if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
return OLE.ERROR_INTERFACE_NOT_FOUND;
objIOleCommandTarget = new IOleCommandTarget(address[0]);
}
int inAddress = 0;
if (in != null){
inAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, Variant.sizeof);
in.getData(inAddress);
}
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() {
int[] ppvObject = new 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)
OLE.error(OLE.ERROR_INVALID_CLASSID, result);
}
return guid;
}
private int GetContainer(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)
COM.MoveMemory(ppContainer, new int[]{0}, 4);
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);
}
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(){
if (appClsid != null){
int[] lplpszProgID = new int[1];
if (COM.ProgIDFromCLSID(appClsid, lplpszProgID) == COM.S_OK) {
int length = OS.GlobalSize(lplpszProgID[0]);
int ptr = OS.GlobalLock(lplpszProgID[0]);
char[] buffer = new char[length];
COM.MoveMemory(buffer, lplpszProgID[0], length);
OS.GlobalUnlock(ptr);
OS.GlobalFree(lplpszProgID[0]);
String result = new String(buffer);
// remove null terminator
int index = result.indexOf("\0");
return result.substring(0, index);
}
}
return null;
}
protected int GetWindow(int phwnd) {
if (phwnd == 0)
return COM.E_INVALIDARG;
if (frame == null) {
COM.MoveMemory(phwnd, new int[] {0}, 4);
return COM.E_NOTIMPL;
}
// Copy the Window's handle into the memory passed in
COM.MoveMemory(phwnd, new int[] {frame.handle}, 4);
return COM.S_OK;
}
private int GetWindowContext(int ppFrame, int ppDoc, int lprcPosRect, int lprcClipRect, int lpFrameInfo) {
if (frame == null || ppFrame == 0)
return COM.E_NOTIMPL;
// fill in frame handle
int iOleInPlaceFrame = frame.getIOleInPlaceFrame();
COM.MoveMemory(ppFrame, new int[] {iOleInPlaceFrame}, 4);
frame.AddRef();
// null out document handle
if (ppDoc != 0) {
COM.MoveMemory(ppDoc, new int[] {0}, 4);
}
// fill in position and clipping info
Rectangle clientArea = this.getClientArea();
Point clientLocation = this.getLocation();
setExtent(clientArea.width - indent.left - indent.right, clientArea.height - indent.top - indent.bottom);
RECT posRect = new RECT();
posRect.left = clientLocation.x + indent.left;
posRect.top = clientLocation.y + indent.top;
posRect.right = clientLocation.x + clientArea.width - indent.right;
posRect.bottom = clientLocation.y + clientArea.height - indent.bottom;
RECT clipRect = new RECT();
Rectangle frameArea = frame.getClientArea();
clipRect.left = frameArea.x;
clipRect.top = frameArea.y;
clipRect.right = frameArea.x + frameArea.width;
clipRect.bottom = frameArea.y + frameArea.height;
if (lprcPosRect != 0) {
OS.MoveMemory(lprcPosRect, posRect, RECT.sizeof);
}
if (lprcClipRect != 0) {
OS.MoveMemory(lprcClipRect, clipRect, 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()) {
int hwnd = shell.handle;
int cAccel = OS.SendMessage(hwnd, OS.WM_APP, 0, 0);
if (cAccel != 0) {
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;
}
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 persistant storage mechanism
int[] address = new int[1];
if (objIOleObject.QueryInterface(COM.IIDIPersistFile, address) != COM.S_OK)
return true;
IPersistStorage permStorage = new IPersistStorage(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;
}
public boolean isFocusControl () {
checkWidget ();
int focusHwnd = OS.GetFocus();
if (focusHwnd == handle) return true;
if (objIOleInPlaceObject == null) return false;
int[] phwnd = new int[1];
objIOleInPlaceObject.GetWindow(phwnd);
if (phwnd[0] == 0) return false;
do {
if (phwnd[0] == focusHwnd) return true;
} while ((focusHwnd = OS.GetParent (focusHwnd)) != 0);
return false;
}
private int OnClose() {
return COM.S_OK;
}
private int OnDataChange(int pFormatetc, int pStgmed) {
return COM.S_OK;
}
private void onDispose(Event e) {
doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE);
releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame
deleteTempStorage();
// remove listeners
removeListener(SWT.Resize, listener);
removeListener(SWT.Move, listener);
removeListener(SWT.Dispose, listener);
frame.removeListener(SWT.Resize, listener);
frame.Release();
frame = null;
}
private void onFocusIn(Event e) {
if (objIOleInPlaceObject == null) return;
if (isFocusControl()) return;
int[] phwnd = new int[1];
objIOleInPlaceObject.GetWindow(phwnd);
if (phwnd[0] == 0) return;
OS.SetFocus(phwnd[0]);
}
private int OnInPlaceActivate() {
active = true;
if (objIOleObject == null)
return COM.S_OK;
int[] ppvObject = new 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;
active = false;
return COM.S_OK;
}
private int OnPosRectChange(int lprcPosRect) {
setObjectRects();
return COM.S_OK;
}
private void onPaint(Event e) {
if (!active && objIUnknown != null) {
SIZE size = getExtent();
Rectangle area = getClientArea();
RECT rect = new RECT();
if (getProgramID().startsWith("Excel.Sheet")) {
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;
}
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) {
Rectangle area = frame.getClientArea();
setBounds(borderWidths.left,
borderWidths.top,
area.width - borderWidths.left - borderWidths.right,
area.height - borderWidths.top - borderWidths.bottom);
setObjectRects();
}
private void OnSave() {
}
private int OnShowWindow(int fShow) {
boolean wasActive = active;
active = (fShow != 0);
if (wasActive != active){
if (active) {
activateInPlaceClient();
} else {
deactivateInPlaceClient();
}
}
return COM.S_OK;
}
private int OnUIActivate() {
return COM.S_OK;
}
private int OnUIDeactivate(int fUndoable) {
// currently, we are ignoring the fUndoable flag
if (frame == null || frame.isDisposed()) return COM.S_OK;
frame.SetActiveObject(0,0);
Shell shell = getShell();
Menu menubar = shell.getMenuBar();
if (menubar == null || menubar.isDisposed())
return COM.S_OK;
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;
}
private IStorage openStorage(IStorage storage, String name) {
int mode = COM.STGM_TRANSACTED | COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE;
int[] ppStg = new int[1];
if (storage.OpenStorage(name, 0, mode, null, 0, ppStg) != COM.S_OK) {
// IStorage does not exist, so create one
mode = mode | COM.STGM_CREATE;
if (storage.CreateStorage(name, mode, 0, 0, ppStg) != COM.S_OK)
return null;
}
return new IStorage(ppStg[0]);
}
protected int QueryInterface(int riid, 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)) {
COM.MoveMemory(ppvObject, new int[] {iUnknown.getAddress()}, 4);
AddRef();
return COM.S_OK;
}
if (COM.IsEqualGUID(guid, COM.IIDIAdviseSink)) {
COM.MoveMemory(ppvObject, new int[] {iAdviseSink.getAddress()}, 4);
AddRef();
return COM.S_OK;
}
if (COM.IsEqualGUID(guid, COM.IIDIOleClientSite)) {
COM.MoveMemory(ppvObject, new int[] {iOleClientSite.getAddress()}, 4);
AddRef();
return COM.S_OK;
}
if (COM.IsEqualGUID(guid, COM.IIDIOleInPlaceSite)) {
COM.MoveMemory(ppvObject, new int[] {iOleInPlaceSite.getAddress()}, 4);
AddRef();
return COM.S_OK;
}
COM.MoveMemory(ppvObject, new int[] {0}, 4);
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) {
int[] address = new 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 (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;
COM.CoFreeUnusedLibraries();
}
public boolean save(File file, boolean includeOleInfo) {
if (includeOleInfo)
return saveToStorageFile(file);
return saveToTraditionalFile(file);
}
private boolean saveFromContents(int address, File file) {
boolean success = false;
IStream tempContents = new IStream(address);
tempContents.AddRef();
try {
FileOutputStream writer = new FileOutputStream(file);
int increment = 1024 * 4;
int pv = COM.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;
}
COM.CoTaskMemFree(pv);
writer.close();
} catch (IOException err) {
}
tempContents.Release();
return success;
}
private boolean saveFromOle10Native(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.
int pv = COM.CoTaskMemAlloc(4);
int[] size = new int[1];
int rc = tempContents.Read(pv, 4, null);
OS.MoveMemory(size, pv, 4);
COM.CoTaskMemFree(pv);
if (rc == COM.S_OK && size[0] > 0) {
// Read the data
byte[] buffer = new byte[size[0]];
pv = COM.CoTaskMemAlloc(size[0]);
rc = tempContents.Read(pv, size[0], null);
OS.MoveMemory(buffer, pv, size[0]);
COM.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;
}
/**
* Saves the document to the specified file and includes OLE spcific inforrmation. 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) {
// 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 persistant storage mechanism
int[] address = new int[1];
if (objIOleObject.QueryInterface(COM.IIDIPersistStorage, address) != COM.S_OK)
return false;
IPersistStorage permStorage = new IPersistStorage(address[0]);
// 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
boolean success = false;
OleFile oleFile = new OleFile(file, null, OleFile.WRITE);
IStorage storage = oleFile.getRootStorage();
storage.AddRef();
if (COM.OleSave(permStorage.getAddress(), storage.getAddress(), false) == COM.S_OK) {
if (storage.Commit(COM.STGC_DEFAULT) == COM.S_OK)
success = true;
}
storage.Release();
oleFile.dispose();
permStorage.Release();
return success;
}
/**
* 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;
int[] address = new 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)
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)
return saveFromOle10Native(address[0], file);
return false;
}
private int Scroll(int scrollExtant) {
return COM.S_OK;
}
void setBorderSpace(RECT newBorderwidth) {
borderWidths = newBorderwidth;
// readjust size and location of client site
Rectangle area = frame.getClientArea();
setBounds(borderWidths.left, borderWidths.top,
area.width - borderWidths.left - borderWidths.right,
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) return;
if (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);
}
}
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
Rectangle clientArea = this.getClientArea();
Point clientLocation = this.getLocation();
setExtent(clientArea.width - indent.left - indent.right, clientArea.height - indent.top - indent.bottom);
RECT posRect = new RECT();
posRect.left = clientLocation.x + indent.left;
posRect.top = clientLocation.y + indent.top;
posRect.right = clientLocation.x + clientArea.width - indent.right;
posRect.bottom = clientLocation.y + clientArea.height - indent.bottom;
RECT clipRect = new RECT();
Rectangle frameArea = frame.getClientArea();
clipRect.left = frameArea.x;
clipRect.top = frameArea.y;
clipRect.right = frameArea.x + frameArea.width;
clipRect.bottom = frameArea.y + frameArea.height;
objIOleInPlaceObject.SetObjectRects(posRect, clipRect);
}
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.
*/
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
int[] ppvObject = new 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 int[] {objIUnknown.getAddress()}, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, 0);
// free the property page information
COM.CoTaskMemFree(caGUID.pElems);
}
private boolean updateStorage() {
if (tempStorage == null) return false;
int[] ppv = new 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.
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.
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;
}
}