1 /*******************************************************************************
2 * Copyright (c) 2000, 2017 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.ole.win32;
18 import org.eclipse.swt.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.*;
21 import org.eclipse.swt.internal.ole.win32.*;
22 import org.eclipse.swt.internal.win32.*;
23 import org.eclipse.swt.widgets.*;
25 * OleClientSite provides a site to manage an embedded OLE Document within a container.
27 * <p>The OleClientSite provides the following capabilities:
29 * <li>creates the in-place editor for a blank document or opening an existing OLE Document
30 * <li>lays the editor out
31 * <li>provides a mechanism for activating and deactivating the Document
32 * <li>provides a mechanism for saving changes made to the document
35 * <p>This object implements the OLE Interfaces IUnknown, IOleClientSite, IAdviseSink,
38 * <p>Note that although this class is a subclass of <code>Composite</code>,
39 * it does not make sense to add <code>Control</code> children to it,
40 * or set a layout on it.
43 * <dt><b>Styles</b> <dd>BORDER
44 * <dt><b>Events</b> <dd>Dispose, Move, Resize
47 * @see <a href="http://www.eclipse.org/swt/snippets/#ole">OLE and ActiveX snippets</a>
48 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: OLEExample, OleWebBrowser</a>
50 public class OleClientSite extends Composite {
52 // Interfaces for this Ole Client Container
53 COMObject iOleClientSite;
54 private COMObject iAdviseSink;
55 private COMObject iOleInPlaceSite;
56 private COMObject iOleDocumentSite;
58 protected GUID appClsid;
59 private GUID objClsid;
62 // References to the associated Frame.
63 protected OleFrame frame;
65 // Access to the embedded/linked Ole Object
66 protected IUnknown objIUnknown;
67 protected IOleObject objIOleObject;
68 protected IViewObject2 objIViewObject2;
69 protected IOleInPlaceObject objIOleInPlaceObject;
70 protected IOleCommandTarget objIOleCommandTarget;
71 protected IOleDocumentView objDocumentView;
73 // Related storage information
74 protected IStorage tempStorage; // IStorage interface of the receiver
76 // Internal state and style information
77 private int aspect; // the display aspect of the embedded object, e.g., DvaspectContent or DvaspectIcon
78 private int type; // Indicates the type of client that can be supported inside this container
79 private boolean isStatic; // Indicates item's display is static, i.e., a bitmap, metafile, etc.
82 private RECT borderWidths = new RECT();
83 private RECT indent = new RECT();
84 private boolean inUpdate = false;
85 private boolean inInit = true;
86 private boolean inDispose = false;
88 private static final String WORDPROGID = "Word.Document"; //$NON-NLS-1$
90 private Listener listener;
92 static final int STATE_NONE = 0;
93 static final int STATE_RUNNING = 1;
94 static final int STATE_INPLACEACTIVE = 2;
95 static final int STATE_UIACTIVE = 3;
96 static final int STATE_ACTIVE = 4;
97 int state = STATE_NONE;
99 protected OleClientSite(Composite parent, int style) {
101 * NOTE: this constructor should never be used by itself because it does
102 * not create an Ole Object
104 super(parent, style);
106 createCOMInterfaces();
108 // install the Ole Frame for this Client Site
109 while (parent != null) {
110 if (parent instanceof OleFrame){
111 frame = (OleFrame)parent;
114 parent = parent.getParent();
116 if (frame == null) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
119 aspect = COM.DVASPECT_CONTENT;
120 type = COM.OLEEMBEDDED;
123 listener = new Listener() {
124 private int nestedFocusEvents = 0;
126 public void handleEvent(Event e) {
129 case SWT.Move : onResize(e); break;
130 case SWT.Dispose : onDispose(e); break;
133 boolean hasFocus = isFocusControl();
137 * Added additional check below to avoid calling OleFrame#onFocusIn() twice,
138 * which other wise lead to Main Menu refresh problem as seen in bug 527268
140 if (nestedFocusEvents == 0 && hasFocus == isFocusControl())
147 if (nestedFocusEvents == 0)
150 case SWT.Paint: onPaint(e); break;
151 case SWT.Traverse: onTraverse(e); break;
152 case SWT.KeyDown: /* required for traversal */ break;
153 case SWT.Activate: isActivated = true; break;
154 case SWT.Deactivate: isActivated = false; break;
156 OLE.error(SWT.ERROR_NOT_IMPLEMENTED);
161 frame.addListener(SWT.Resize, listener);
162 frame.addListener(SWT.Move, listener);
163 addListener(SWT.Dispose, listener);
164 addListener(SWT.FocusIn, listener);
165 addListener(SWT.FocusOut, listener);
166 addListener(SWT.Paint, listener);
167 addListener(SWT.Traverse, listener);
168 addListener(SWT.KeyDown, listener);
169 addListener(SWT.Activate, listener);
170 addListener(SWT.Deactivate, listener);
173 * Create an OleClientSite child widget using the OLE Document type associated with the
174 * specified file. The OLE Document type is determined either through header information in the file
175 * or through a Registry entry for the file extension. Use style bits to select a particular look
176 * or set of properties.
178 * @param parent a composite widget; must be an OleFrame
179 * @param style the bitwise OR'ing of widget styles
180 * @param file the file that is to be opened in this OLE Document
182 * @exception IllegalArgumentException
183 * <ul><li>ERROR_NULL_ARGUMENT when the parent is null
184 * <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame</ul>
185 * @exception SWTException
186 * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
187 * <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
188 * <li>ERROR_CANNOT_OPEN_FILE when failed to open file
189 * <li>ERROR_INTERFACE_NOT_FOUND when unable to create callbacks for OLE Interfaces
190 * <li>ERROR_INVALID_CLASSID
193 public OleClientSite(Composite parent, int style, File file) {
197 if (file == null || file.isDirectory() || !file.exists())
198 OLE.error(SWT.ERROR_INVALID_ARGUMENT);
200 // Is there an associated CLSID?
201 GUID fileClsid = new GUID();
202 char[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
203 int result = COM.GetClassFile(fileName, fileClsid);
204 if (result != COM.S_OK) OLE.error(OLE.ERROR_INVALID_CLASSID, result);
205 // associated CLSID may not be installed on this machine
206 String progID = getProgID(fileClsid);
207 if (progID == null) OLE.error(OLE.ERROR_INVALID_CLASSID, result);
209 appClsid = fileClsid;
210 OleCreate(appClsid, fileClsid, fileName, file);
211 } catch (SWTException e) {
213 disposeCOMInterfaces();
218 * Create an OleClientSite child widget to edit a blank document using the specified OLE Document
219 * application. Use style bits to select a particular look or set of properties.
221 * @param parent a composite widget; must be an OleFrame
222 * @param style the bitwise OR'ing of widget styles
223 * @param progId the unique program identifier of an OLE Document application;
224 * the value of the ProgID key or the value of the VersionIndependentProgID key specified
225 * in the registry for the desired OLE Document (for example, the VersionIndependentProgID
226 * for Word is Word.Document)
228 * @exception IllegalArgumentException
230 * <li>ERROR_NULL_ARGUMENT when the parent is null
231 * <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
233 * @exception SWTException
234 * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
235 * <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
236 * <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
239 public OleClientSite(Composite parent, int style, String progId) {
242 appClsid = getClassID(progId);
243 if (appClsid == null)
244 OLE.error(OLE.ERROR_INVALID_CLASSID);
246 // Open a temporary storage object
247 tempStorage = createTempStorage();
249 // Create ole object with storage object
250 long[] address = new long[1];
252 * Bug in ICA Client 2.7. The creation of the IOleObject fails if the client
253 * site is provided to OleCreate(). The fix is to detect that the program
254 * id is an ICA Client and do not pass a client site to OleCreate().
255 * IOleObject.SetClientSite() is called later on.
257 long clientSite = isICAClient() ? 0 : iOleClientSite.getAddress();
258 int result = COM.OleCreate(appClsid, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, clientSite, tempStorage.getAddress(), address);
259 if (result != COM.S_OK)
260 OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
262 objIUnknown = new IUnknown(address[0]);
265 addObjectReferences();
267 if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
269 } catch (SWTException e) {
271 disposeCOMInterfaces();
276 * Create an OleClientSite child widget to edit the specified file using the specified OLE Document
277 * application. Use style bits to select a particular look or set of properties.
279 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
280 * API for <code>OleClientSite</code>. It is marked public only so that it
281 * can be shared within the packages provided by SWT. It is not
282 * available on all platforms, and should never be called from
285 * @param parent a composite widget; must be an OleFrame
286 * @param style the bitwise OR'ing of widget styles
287 * @param progId the unique program identifier of am OLE Document application;
288 * the value of the ProgID key or the value of the VersionIndependentProgID key specified
289 * in the registry for the desired OLE Document (for example, the VersionIndependentProgID
290 * for Word is Word.Document)
291 * @param file the file that is to be opened in this OLE Document
293 * @exception IllegalArgumentException
294 * <ul><li>ERROR_NULL_ARGUMENT when the parent is null
295 * <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame</ul>
296 * @exception SWTException
297 * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
298 * <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
299 * <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
300 * <li>ERROR_CANNOT_OPEN_FILE when failed to open file
303 * @noreference This method is not intended to be referenced by clients.
305 public OleClientSite(Composite parent, int style, String progId, File file) {
308 if (file == null || file.isDirectory() || !file.exists()) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
309 appClsid = getClassID(progId);
310 if (appClsid == null) OLE.error(OLE.ERROR_INVALID_CLASSID);
312 // Are we opening this file with the preferred OLE object?
313 char[] fileName = (file.getAbsolutePath()+"\0").toCharArray();
314 GUID fileClsid = new GUID();
315 COM.GetClassFile(fileName, fileClsid);
317 OleCreate(appClsid, fileClsid, fileName, file);
318 } catch (SWTException e) {
320 disposeCOMInterfaces();
325 void OleCreate(GUID appClsid, GUID fileClsid, char[] fileName, File file) {
327 /* Bug in Windows. In some machines running Windows Vista and
328 * Office 2007, OleCreateFromFile() fails to open files from
329 * Office Word 97 - 2003 and in some other cases it fails to
330 * save files due to a lock. The fix is to detect this case and
331 * create the activeX using CoCreateInstance().
333 boolean isOffice2007 = isOffice2007(true);
334 if (!isOffice2007 && COM.IsEqualGUID(appClsid, fileClsid)){
335 // Using the same application that created file, therefore, use default mechanism.
336 tempStorage = createTempStorage();
337 // Create ole object with storage object
338 long[] address = new long[1];
339 int result = COM.OleCreateFromFile(appClsid, fileName, COM.IIDIUnknown, COM.OLERENDER_DRAW, null, iOleClientSite.getAddress(), tempStorage.getAddress(), address);
340 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
341 objIUnknown = new IUnknown(address[0]);
343 // Not using the same application that created file, therefore, copy from original file to a new storage file
344 IStorage storage = null;
345 if (COM.StgIsStorageFile(fileName) == COM.S_OK) {
346 long[] address = new long[1];
347 int mode = COM.STGM_READ | COM.STGM_TRANSACTED | COM.STGM_SHARE_EXCLUSIVE;
348 int result = COM.StgOpenStorage(fileName, 0, mode, 0, 0, address); //Does an AddRef if successful
349 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
350 storage = new IStorage(address[0]);
352 // Original file is not a Storage file so copy contents to a stream in a new storage file
353 long[] address = new long[1];
354 int mode = COM.STGM_READWRITE | COM.STGM_DIRECT | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
355 int result = COM.StgCreateDocfile(null, mode | COM.STGM_DELETEONRELEASE, 0, address); // Increments ref count if successful
356 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
357 storage = new IStorage(address[0]);
358 // Create a stream on the storage object.
359 // Word does not follow the standard and does not use "CONTENTS" as the name of
360 // its primary stream
361 String streamName = "CONTENTS"; //$NON-NLS-1$
362 GUID wordGUID = getClassID(WORDPROGID);
363 if (wordGUID != null && COM.IsEqualGUID(appClsid, wordGUID)) streamName = "WordDocument"; //$NON-NLS-1$
364 if (isOffice2007) streamName = "Package"; //$NON-NLS-1$
365 address = new long[1];
366 result = storage.CreateStream(streamName, mode, 0, 0, address); // Increments ref count if successful
367 if (result != COM.S_OK) {
369 OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
371 IStream stream = new IStream(address[0]);
373 // Copy over data in file to named stream
374 FileInputStream fileInput = new FileInputStream(file);
375 int increment = 1024*4;
376 byte[] buffer = new byte[increment];
378 while((count = fileInput.read(buffer)) > 0){
379 long pv = OS.CoTaskMemAlloc(count);
380 OS.MoveMemory(pv, buffer, count);
381 result = stream.Write(pv, count, null) ;
382 OS.CoTaskMemFree(pv);
383 if (result != COM.S_OK) {
387 OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
391 stream.Commit(COM.STGC_DEFAULT);
393 } catch (IOException err) {
396 OLE.error(OLE.ERROR_CANNOT_OPEN_FILE);
400 // Open a temporary storage object
401 tempStorage = createTempStorage();
402 // Copy over contents of file
403 int result = storage.CopyTo(0, null, null, tempStorage.getAddress());
405 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
408 long[] ppv = new long[1];
409 result = COM.CoCreateInstance(appClsid, 0, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, COM.IIDIUnknown, ppv);
410 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
411 objIUnknown = new IUnknown(ppv[0]);
412 // get the persistent storage of the ole client
414 result = objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv);
415 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
416 IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]);
417 // load the contents of the file into the ole client site
418 result = iPersistStorage.Load(tempStorage.getAddress());
419 iPersistStorage.Release();
420 if (result != COM.S_OK)OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
424 addObjectReferences();
426 if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
428 protected void addObjectReferences() {
430 long[] ppvObject = new long[1];
431 if (objIUnknown.QueryInterface(COM.IIDIPersist, ppvObject) == COM.S_OK) {
432 IPersist objIPersist = new IPersist(ppvObject[0]);
433 GUID tempid = new GUID();
434 if (objIPersist.GetClassID(tempid) == COM.S_OK)
436 objIPersist.Release();
440 ppvObject = new long[1];
441 int result = objIUnknown.QueryInterface(COM.IIDIViewObject2, ppvObject);
442 if (result != COM.S_OK)
443 OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND, result);
444 objIViewObject2 = new IViewObject2(ppvObject[0]);
445 objIViewObject2.SetAdvise(aspect, 0, iAdviseSink.getAddress());
448 ppvObject = new long[1];
449 result = objIUnknown.QueryInterface(COM.IIDIOleObject, ppvObject);
450 if (result != COM.S_OK)
451 OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND, result);
452 objIOleObject = new IOleObject(ppvObject[0]);
454 * Feature in Windows. Despite the fact that the clientSite was provided during the
455 * creation of the OleObject (which is required by WMP11 - see bug 173556),
456 * some applications choose to ignore this optional parameter (see bug 211663)
457 * during OleCreate. The fix is to check whether the clientSite has already been set
458 * and set it. Note that setting it twice can result in assert failures.
460 long[] ppvClientSite = new long[1];
461 result = objIOleObject.GetClientSite(ppvClientSite);
462 if (ppvClientSite[0] == 0) {
463 objIOleObject.SetClientSite(iOleClientSite.getAddress());
465 Release(); // GetClientSite performs an AddRef so we must release it.
467 int[] pdwConnection = new int[1];
468 objIOleObject.Advise(iAdviseSink.getAddress(), pdwConnection);
469 objIOleObject.SetHostNames("main", "main"); //$NON-NLS-1$ //$NON-NLS-2$
471 // Notify the control object that it is embedded in an OLE container
472 COM.OleSetContainedObject(objIUnknown.getAddress(), true);
474 // Is OLE object linked or embedded?
475 ppvObject = new long[1];
476 if (objIUnknown.QueryInterface(COM.IIDIOleLink, ppvObject) == COM.S_OK) {
477 IOleLink objIOleLink = new IOleLink(ppvObject[0]);
478 long[] ppmk = new long[1];
479 if (objIOleLink.GetSourceMoniker(ppmk) == COM.S_OK) {
480 new IUnknown(ppmk[0]).Release();
481 type = COM.OLELINKED;
482 objIOleLink.BindIfRunning();
486 objIOleLink.Release();
489 protected int AddRef() {
493 private int CanInPlaceActivate() {
494 if (aspect == COM.DVASPECT_CONTENT && type == COM.OLEEMBEDDED)
499 private int ContextSensitiveHelp(int fEnterMode) {
502 protected void createCOMInterfaces() {
504 iOleClientSite = new COMObject(new int[]{2, 0, 0, 0, 3, 1, 0, 1, 0}){
506 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
508 public long method1(long[] args) {return AddRef();}
510 public long method2(long[] args) {return Release();}
512 public long method3(long[] args) {return SaveObject();}
513 // method4 GetMoniker - not implemented
515 public long method5(long[] args) {return GetContainer(args[0]);}
517 public long method6(long[] args) {return ShowObject();}
519 public long method7(long[] args) {return OnShowWindow((int)args[0]);}
520 // method8 RequestNewObjectLayout - not implemented
523 iAdviseSink = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 0, 0}){
525 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
527 public long method1(long[] args) {return AddRef();}
529 public long method2(long[] args) {return Release();}
531 public long method3(long[] args) {return OnDataChange(args[0], args[1]);}
533 public long method4(long[] args) {return OnViewChange((int)args[0], (int)args[1]);}
534 //method5 OnRename - not implemented
536 public long method6(long[] args) {OnSave();return 0;}
538 public long method7(long[] args) {return OnClose();}
541 iOleInPlaceSite = new COMObject(new int[]{2, 0, 0, 1, 1, 0, 0, 0, 5, 1, 1, 0, 0, 0, 1}){
543 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
545 public long method1(long[] args) {return AddRef();}
547 public long method2(long[] args) {return Release();}
549 public long method3(long[] args) {return GetWindow(args[0]);}
551 public long method4(long[] args) {return ContextSensitiveHelp((int)args[0]);}
553 public long method5(long[] args) {return CanInPlaceActivate();}
555 public long method6(long[] args) {return OnInPlaceActivate();}
557 public long method7(long[] args) {return OnUIActivate();}
559 public long method8(long[] args) {return GetWindowContext(args[0], args[1], args[2], args[3], args[4]);}
561 public long method9(long[] args) {return Scroll(args[0]);}
563 public long method10(long[] args) {return OnUIDeactivate((int)args[0]);}
565 public long method11(long[] args) {return OnInPlaceDeactivate();}
566 // method12 DiscardUndoState - not implemented
567 // method13 DeactivateAndUndoChange - not implemented
569 public long method14(long[] args) {return OnPosRectChange(args[0]);}
572 iOleDocumentSite = new COMObject(new int[]{2, 0, 0, 1}){
574 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
576 public long method1(long[] args) {return AddRef();}
578 public long method2(long[] args) {return Release();}
580 public long method3(long[] args) {return ActivateMe(args[0]);}
583 protected IStorage createTempStorage() {
584 long[] tempStorage = new long[1];
585 int grfMode = COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_DELETEONRELEASE;
586 int result = COM.StgCreateDocfile(null, grfMode, 0, tempStorage);
587 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_CREATE_FILE, result);
588 return new IStorage(tempStorage[0]);
591 * Deactivates an active in-place object and discards the object's undo state.
593 public void deactivateInPlaceClient() {
594 if (objIOleInPlaceObject != null) {
595 objIOleInPlaceObject.InPlaceDeactivate();
598 private void deleteTempStorage() {
599 //Destroy this item's contents in the temp root IStorage.
600 if (tempStorage != null){
601 tempStorage.Release();
605 protected void disposeCOMInterfaces() {
606 if (iOleClientSite != null)
607 iOleClientSite.dispose();
608 iOleClientSite = null;
610 if (iAdviseSink != null)
611 iAdviseSink.dispose();
614 if (iOleInPlaceSite != null)
615 iOleInPlaceSite.dispose();
616 iOleInPlaceSite = null;
618 if (iOleDocumentSite != null)
619 iOleDocumentSite.dispose();
620 iOleDocumentSite = null;
623 * Requests that the OLE Document or ActiveX Control perform an action; actions are almost always
624 * changes to the activation state.
626 * @param verb the operation that is requested. This is one of the OLE.OLEIVERB_ values
628 * @return an HRESULT value indicating the success of the operation request; OLE.S_OK indicates
631 public int doVerb(int verb) {
632 // Not all OLE clients (for example PowerPoint) can be set into the running state in the constructor.
633 // The fix is to ensure that the client is in the running state before invoking any verb on it.
634 if (state == STATE_NONE) {
635 if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
637 if (state == STATE_NONE || isStatic)
641 RECT rect = new RECT();
642 OS.GetClientRect(handle, rect);
643 int result = objIOleObject.DoVerb(verb, null, iOleClientSite.getAddress(), 0, handle, rect);
645 if (state != STATE_RUNNING && inInit) {
652 * Asks the OLE Document or ActiveX Control to execute a command from a standard
653 * list of commands. The OLE Document or ActiveX Control must support the IOleCommandTarget
654 * interface. The OLE Document or ActiveX Control does not have to support all the commands
655 * in the standard list. To check if a command is supported, you can call queryStatus with
658 * @param cmdID the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
660 * @param options the optional flags; these are the OLE.OLECMDEXECOPT_ values
661 * @param in the argument for the command
662 * @param out the return value of the command
664 * @return an HRESULT value; OLE.S_OK is returned if successful
667 public int exec(int cmdID, int options, Variant in, Variant out) {
669 if (objIOleCommandTarget == null) {
670 long[] address = new long[1];
671 if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
672 return OLE.ERROR_INTERFACE_NOT_FOUND;
673 objIOleCommandTarget = new IOleCommandTarget(address[0]);
678 inAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
679 in.getData(inAddress);
683 outAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
684 out.getData(outAddress);
687 int result = objIOleCommandTarget.Exec(null, cmdID, options, inAddress, outAddress);
690 COM.VariantClear(inAddress);
691 OS.GlobalFree(inAddress);
693 if (outAddress != 0) {
694 out.setData(outAddress);
695 COM.VariantClear(outAddress);
696 OS.GlobalFree(outAddress);
701 IDispatch getAutomationObject() {
702 long[] ppvObject = new long[1];
703 if (objIUnknown.QueryInterface(COM.IIDIDispatch, ppvObject) != COM.S_OK)
705 return new IDispatch(ppvObject[0]);
707 protected GUID getClassID(String clientName) {
708 // create a GUID struct to hold the result
709 GUID guid = new GUID();
711 // create a null terminated array of char
712 char[] buffer = null;
713 if (clientName != null) {
714 int count = clientName.length();
715 buffer = new char[count + 1];
716 clientName.getChars(0, count, buffer, 0);
718 if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){
719 int result = COM.CLSIDFromString(buffer, guid);
720 if (result != COM.S_OK) return null;
724 private int GetContainer(long ppContainer) {
725 /* Simple containers that do not support links to their embedded
726 * objects probably do not need to implement this method. Instead,
727 * they can return E_NOINTERFACE and set ppContainer to NULL.
729 if (ppContainer != 0)
730 OS.MoveMemory(ppContainer, new long[]{0}, C.PTR_SIZEOF);
731 return COM.E_NOINTERFACE;
733 private SIZE getExtent() {
734 SIZE sizel = new SIZE();
735 // get the current size of the embedded OLENatives object
736 if (objIOleObject != null) {
737 if ( objIViewObject2 != null && !COM.OleIsRunning(objIOleObject.getAddress())) {
738 objIViewObject2.GetExtent(aspect, -1, 0, sizel);
740 objIOleObject.GetExtent(aspect, sizel);
743 return xFormHimetricToPixels(sizel);
746 * Returns the indent value that would be used to compute the clipping area
747 * of the active X object.
749 * NOTE: The indent value is no longer being used by the client site.
751 * @return the rectangle representing the indent
753 public Rectangle getIndent() {
754 return new Rectangle(indent.left, indent.right, indent.top, indent.bottom);
757 * Returns the program ID of the OLE Document or ActiveX Control.
759 * @return the program ID of the OLE Document or ActiveX Control
761 public String getProgramID(){
762 return getProgID(appClsid);
764 String getProgID(GUID clsid) {
766 long[] lplpszProgID = new long[1];
767 if (COM.ProgIDFromCLSID(clsid, lplpszProgID) == COM.S_OK) {
768 long hMem = lplpszProgID[0];
769 int length = OS.GlobalSize(hMem);
770 long ptr = OS.GlobalLock(hMem);
771 char[] buffer = new char[length];
772 OS.MoveMemory(buffer, ptr, length);
773 OS.GlobalUnlock(hMem);
776 String result = new String(buffer);
777 // remove null terminator
778 int index = result.indexOf("\0");
779 return result.substring(0, index);
784 int ActivateMe(long pViewToActivate) {
785 if (pViewToActivate == 0) {
786 long[] ppvObject = new long[1];
787 if (objIUnknown.QueryInterface(COM.IIDIOleDocument, ppvObject) != COM.S_OK) return COM.E_FAIL;
788 IOleDocument objOleDocument = new IOleDocument(ppvObject[0]);
789 if (objOleDocument.CreateView(iOleInPlaceSite.getAddress(), 0, 0, ppvObject) != COM.S_OK) return COM.E_FAIL;
790 objOleDocument.Release();
791 objDocumentView = new IOleDocumentView(ppvObject[0]);
793 objDocumentView = new IOleDocumentView(pViewToActivate);
794 objDocumentView.AddRef();
795 objDocumentView.SetInPlaceSite(iOleInPlaceSite.getAddress());
797 objDocumentView.UIActivate(1);//TRUE
798 RECT rect = getRect();
799 objDocumentView.SetRect(rect);
800 objDocumentView.Show(1);//TRUE
803 protected int GetWindow(long phwnd) {
805 return COM.E_INVALIDARG;
807 OS.MoveMemory(phwnd, new long[] {0}, C.PTR_SIZEOF);
808 return COM.E_NOTIMPL;
811 // Copy the Window's handle into the memory passed in
812 OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF);
816 Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels
817 RECT rect = new RECT();
820 rect.right = area.x + area.width;
821 rect.bottom = area.y + area.height;
824 private int GetWindowContext(long ppFrame, long ppDoc, long lprcPosRect, long lprcClipRect, long lpFrameInfo) {
825 if (frame == null || ppFrame == 0)
826 return COM.E_NOTIMPL;
828 // fill in frame handle
829 long iOleInPlaceFrame = frame.getIOleInPlaceFrame();
830 OS.MoveMemory(ppFrame, new long[] {iOleInPlaceFrame}, C.PTR_SIZEOF);
833 // null out document handle
834 if (ppDoc != 0) OS.MoveMemory(ppDoc, new long[] {0}, C.PTR_SIZEOF);
836 // fill in position and clipping info
837 RECT rect = getRect();
838 if (lprcPosRect != 0) OS.MoveMemory(lprcPosRect, rect, RECT.sizeof);
839 if (lprcClipRect != 0) OS.MoveMemory(lprcClipRect, rect, RECT.sizeof);
842 OLEINPLACEFRAMEINFO frameInfo = new OLEINPLACEFRAMEINFO();
843 frameInfo.cb = OLEINPLACEFRAMEINFO.sizeof;
844 frameInfo.fMDIApp = 0;
845 frameInfo.hwndFrame = frame.handle;
846 Shell shell = getShell();
847 Menu menubar = shell.getMenuBar();
848 if (menubar != null && !menubar.isDisposed()) {
849 long hwnd = shell.handle;
850 int cAccel = (int)OS.SendMessage(hwnd, OS.WM_APP, 0, 0);
852 long hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
854 frameInfo.cAccelEntries = cAccel;
855 frameInfo.haccel = hAccel;
859 COM.MoveMemory(lpFrameInfo, frameInfo, OLEINPLACEFRAMEINFO.sizeof);
863 boolean isICAClient() {
864 return getProgramID().startsWith("Citrix.ICAClient"); //$NON-NLS-1$
867 * Returns whether ole document is dirty by checking whether the content
868 * of the file representing the document is dirty.
870 * @return <code>true</code> if the document has been modified,
871 * <code>false</code> otherwise.
874 public boolean isDirty() {
876 * Note: this method must return true unless it is absolutely clear that the
877 * contents of the Ole Document do not differ from the contents in the file
878 * on the file system.
881 // Get access to the persistent storage mechanism
882 long[] address = new long[1];
883 if (objIOleObject.QueryInterface(COM.IIDIPersistFile, address) != COM.S_OK)
885 IPersistFile permStorage = new IPersistFile(address[0]);
886 // Are the contents of the permanent storage different from the file?
887 int result = permStorage.IsDirty();
888 permStorage.Release();
889 if (result == COM.S_FALSE) return false;
893 public boolean isFocusControl () {
895 long focusHwnd = OS.GetFocus();
896 if (objIOleInPlaceObject == null) return (handle == focusHwnd);
897 long[] phwnd = new long[1];
898 objIOleInPlaceObject.GetWindow(phwnd);
899 while (focusHwnd != 0) {
900 if (phwnd[0] == focusHwnd) return true;
901 focusHwnd = OS.GetParent(focusHwnd);
905 private boolean isOffice2007(boolean program) {
906 String programID = getProgramID();
907 if (programID == null) return false;
909 int lastDot = programID.lastIndexOf('.');
911 programID = programID.substring(0, lastDot);
912 GUID guid = getClassID(programID);
913 programID = getProgID(guid);
914 if (programID == null) return false;
917 if (programID.equals("Word.Document.12")) return true; //$NON-NLS-1$
918 if (programID.equals("Excel.Sheet.12")) return true; //$NON-NLS-1$
919 if (programID.equals("PowerPoint.Show.12")) return true; //$NON-NLS-1$
922 private int OnClose() {
925 private int OnDataChange(long pFormatetc, long pStgmed) {
928 private void onDispose(Event e) {
932 removeListener(SWT.Dispose, listener);
933 removeListener(SWT.FocusIn, listener);
934 removeListener(SWT.FocusOut, listener);
935 removeListener(SWT.Paint, listener);
936 removeListener(SWT.Traverse, listener);
937 removeListener(SWT.KeyDown, listener);
939 if (state != STATE_NONE)
940 doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE);
941 deactivateInPlaceClient();
942 releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame
945 frame.removeListener(SWT.Resize, listener);
946 frame.removeListener(SWT.Move, listener);
951 void onFocusIn(Event e) {
952 if (inDispose) return;
953 if (state != STATE_UIACTIVE) {
954 long[] ppvObject = new long[1];
955 if (objIUnknown.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) {
956 IOleInPlaceObject objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]);
957 objIOleInPlaceObject.Release();
958 doVerb(OLE.OLEIVERB_SHOW);
961 if (objIOleInPlaceObject == null) return;
962 if (isFocusControl()) return;
963 long[] phwnd = new long[1];
964 objIOleInPlaceObject.GetWindow(phwnd);
965 if (phwnd[0] == 0) return;
966 OS.SetFocus(phwnd[0]);
968 void onFocusOut(Event e) {
970 private int OnInPlaceActivate() {
971 state = STATE_INPLACEACTIVE;
972 frame.setCurrentDocument(this);
973 if (objIOleObject == null)
975 long[] ppvObject = new long[1];
976 if (objIOleObject.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) {
977 objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]);
981 private int OnInPlaceDeactivate() {
982 if (objIOleInPlaceObject != null) objIOleInPlaceObject.Release();
983 objIOleInPlaceObject = null;
984 state = STATE_RUNNING;
986 Shell shell = getShell();
987 if (isFocusControl() || frame.isFocusControl()) {
988 shell.traverse(SWT.TRAVERSE_TAB_NEXT);
992 private int OnPosRectChange(long lprcPosRect) {
993 Point size = DPIUtil.autoScaleUp(getSize()); // To Pixels
994 setExtent(size.x, size.y);
997 private void onPaint(Event e) {
998 if (state == STATE_RUNNING || state == STATE_INPLACEACTIVE) {
999 SIZE size = getExtent();
1000 Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels
1001 RECT rect = new RECT();
1002 if (getProgramID().startsWith("Excel.Sheet")) { //$NON-NLS-1$
1003 rect.left = area.x; rect.right = area.x + (area.height * size.cx / size.cy);
1004 rect.top = area.y; rect.bottom = area.y + area.height;
1006 rect.left = area.x; rect.right = area.x + size.cx;
1007 rect.top = area.y; rect.bottom = area.y + size.cy;
1010 long pArea = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, RECT.sizeof);
1011 OS.MoveMemory(pArea, rect, RECT.sizeof);
1012 COM.OleDraw(objIUnknown.getAddress(), aspect, e.gc.handle, pArea);
1013 OS.GlobalFree(pArea);
1016 private void onResize(Event e) {
1019 private void OnSave() {
1021 private int OnShowWindow(int fShow) {
1024 private int OnUIActivate() {
1025 if (objIOleInPlaceObject == null) return COM.E_FAIL;
1026 state = STATE_UIACTIVE;
1027 long[] phwnd = new long[1];
1028 if (objIOleInPlaceObject.GetWindow(phwnd) == COM.S_OK) {
1029 OS.SetWindowPos(phwnd[0], OS.HWND_TOP, 0, 0, 0, 0, OS.SWP_NOSIZE | OS.SWP_NOMOVE);
1033 int OnUIDeactivate(int fUndoable) {
1034 // currently, we are ignoring the fUndoable flag
1035 if (frame == null || frame.isDisposed()) return COM.S_OK;
1036 state = STATE_INPLACEACTIVE;
1037 frame.SetActiveObject(0,0);
1039 Shell shell = getShell();
1040 if (isFocusControl() || frame.isFocusControl()) {
1041 shell.traverse(SWT.TRAVERSE_TAB_NEXT);
1043 Menu menubar = shell.getMenuBar();
1044 if (menubar == null || menubar.isDisposed())
1047 long shellHandle = shell.handle;
1048 OS.SetMenu(shellHandle, menubar.handle);
1049 return COM.OleSetMenuDescriptor(0, shellHandle, 0, 0, 0);
1051 private void onTraverse(Event event) {
1052 switch (event.detail) {
1053 case SWT.TRAVERSE_ESCAPE:
1054 case SWT.TRAVERSE_RETURN:
1055 case SWT.TRAVERSE_TAB_NEXT:
1056 case SWT.TRAVERSE_TAB_PREVIOUS:
1057 case SWT.TRAVERSE_PAGE_NEXT:
1058 case SWT.TRAVERSE_PAGE_PREVIOUS:
1059 case SWT.TRAVERSE_MNEMONIC:
1064 private int OnViewChange(int dwAspect, int lindex) {
1067 protected int QueryInterface(long riid, long ppvObject) {
1069 if (riid == 0 || ppvObject == 0)
1070 return COM.E_NOINTERFACE;
1071 GUID guid = new GUID();
1072 COM.MoveMemory(guid, riid, GUID.sizeof);
1074 if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIOleClientSite)) {
1075 OS.MoveMemory(ppvObject, new long[] {iOleClientSite.getAddress()}, C.PTR_SIZEOF);
1079 if (COM.IsEqualGUID(guid, COM.IIDIAdviseSink)) {
1080 OS.MoveMemory(ppvObject, new long[] {iAdviseSink.getAddress()}, C.PTR_SIZEOF);
1084 if (COM.IsEqualGUID(guid, COM.IIDIOleInPlaceSite)) {
1085 OS.MoveMemory(ppvObject, new long[] {iOleInPlaceSite.getAddress()}, C.PTR_SIZEOF);
1089 if (COM.IsEqualGUID(guid, COM.IIDIOleDocumentSite )) {
1090 String progID = getProgramID();
1091 if (!progID.startsWith("PowerPoint")) { //$NON-NLS-1$
1092 OS.MoveMemory(ppvObject, new long[] {iOleDocumentSite.getAddress()}, C.PTR_SIZEOF);
1097 OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
1098 return COM.E_NOINTERFACE;
1101 * Returns the status of the specified command. The status is any bitwise OR'd combination of
1102 * SWTOLE.OLECMDF_SUPPORTED, SWTOLE.OLECMDF_ENABLED, SWTOLE.OLECMDF_LATCHED, SWTOLE.OLECMDF_NINCHED.
1103 * You can query the status of a command before invoking it with OleClientSite.exec. The
1104 * OLE Document or ActiveX Control must support the IOleCommandTarget to make use of this method.
1106 * @param cmd the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
1109 * @return the status of the specified command or 0 if unable to query the OLE Object; these are the
1110 * OLE.OLECMDF_ values
1112 public int queryStatus(int cmd) {
1114 if (objIOleCommandTarget == null) {
1115 long[] address = new long[1];
1116 if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
1118 objIOleCommandTarget = new IOleCommandTarget(address[0]);
1121 OLECMD olecmd = new OLECMD();
1124 int result = objIOleCommandTarget.QueryStatus(null, 1, olecmd, 0);
1126 if (result != COM.S_OK) return 0;
1130 protected int Release() {
1133 if (refCount == 0) {
1134 disposeCOMInterfaces();
1138 protected void releaseObjectInterfaces() {
1140 if (objIOleInPlaceObject!= null)
1141 objIOleInPlaceObject.Release();
1142 objIOleInPlaceObject = null;
1144 if (objIOleObject != null) {
1145 objIOleObject.Close(COM.OLECLOSE_NOSAVE);
1146 objIOleObject.Release();
1148 objIOleObject = null;
1150 if (objDocumentView != null){
1151 objDocumentView.Release();
1153 objDocumentView = null;
1155 if (objIViewObject2 != null) {
1156 objIViewObject2.SetAdvise(aspect, 0, 0);
1157 objIViewObject2.Release();
1159 objIViewObject2 = null;
1161 if (objIOleCommandTarget != null)
1162 objIOleCommandTarget.Release();
1163 objIOleCommandTarget = null;
1165 if (objIUnknown != null){
1166 objIUnknown.Release();
1170 if (COM.FreeUnusedLibraries) {
1171 COM.CoFreeUnusedLibraries();
1175 * Saves the document to the specified file and includes OLE specific information if specified.
1176 * This method must <b>only</b> be used for files that have an OLE Storage format. For example,
1177 * a word file edited with Word.Document should be saved using this method because there is
1178 * formating information that should be stored in the OLE specific Storage format.
1180 * @param file the file to which the changes are to be saved
1181 * @param includeOleInfo the flag to indicate whether OLE specific information should be saved.
1183 * @return true if the save was successful
1185 public boolean save(File file, boolean includeOleInfo) {
1187 * Bug in Office 2007. Saving Office 2007 documents to compound file storage object
1188 * causes the output file to be corrupted. The fix is to detect Office 2007 documents
1189 * using the program ID and save only the content of the 'Package' stream.
1191 if (isOffice2007(false)) {
1192 return saveOffice2007(file);
1195 return saveToStorageFile(file);
1196 return saveToTraditionalFile(file);
1198 private boolean saveFromContents(long address, File file) {
1200 boolean success = false;
1202 IStream tempContents = new IStream(address);
1203 tempContents.AddRef();
1206 FileOutputStream writer = new FileOutputStream(file);
1208 int increment = 1024 * 4;
1209 long pv = OS.CoTaskMemAlloc(increment);
1210 int[] pcbWritten = new int[1];
1211 while (tempContents.Read(pv, increment, pcbWritten) == COM.S_OK && pcbWritten[0] > 0) {
1212 byte[] buffer = new byte[ pcbWritten[0]];
1213 OS.MoveMemory(buffer, pv, pcbWritten[0]);
1214 writer.write(buffer); // Note: if file does not exist, this will create the file the
1215 // first time it is called
1218 OS.CoTaskMemFree(pv);
1222 } catch (IOException err) {
1225 tempContents.Release();
1229 private boolean saveFromOle10Native(long address, File file) {
1231 boolean success = false;
1233 IStream tempContents = new IStream(address);
1234 tempContents.AddRef();
1236 // The "\1Ole10Native" stream contains a DWORD header whose value is the length
1237 // of the native data that follows.
1238 long pv = OS.CoTaskMemAlloc(4);
1239 int[] size = new int[1];
1240 int rc = tempContents.Read(pv, 4, null);
1241 OS.MoveMemory(size, pv, 4);
1242 OS.CoTaskMemFree(pv);
1243 if (rc == COM.S_OK && size[0] > 0) {
1246 byte[] buffer = new byte[size[0]];
1247 pv = OS.CoTaskMemAlloc(size[0]);
1248 rc = tempContents.Read(pv, size[0], null);
1249 OS.MoveMemory(buffer, pv, size[0]);
1250 OS.CoTaskMemFree(pv);
1252 // open the file and write data into it
1254 FileOutputStream writer = new FileOutputStream(file);
1255 writer.write(buffer); // Note: if file does not exist, this will create the file
1259 } catch (IOException err) {
1262 tempContents.Release();
1266 private int SaveObject() {
1272 private boolean saveOffice2007(File file) {
1273 if (file == null || file.isDirectory()) return false;
1274 if (!updateStorage()) return false;
1275 boolean result = false;
1277 /* Excel fails to open the package stream when the PersistStorage is not in hands off mode */
1278 long[] ppv = new long[1];
1279 IPersistStorage iPersistStorage = null;
1280 if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) == COM.S_OK) {
1281 iPersistStorage = new IPersistStorage(ppv[0]);
1282 tempStorage.AddRef();
1283 iPersistStorage.HandsOffStorage();
1285 long[] address = new long[1];
1286 int grfMode = COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE;
1287 if (tempStorage.OpenStream("Package", 0, grfMode, 0, address) == COM.S_OK) { //$NON-NLS-1$
1288 result = saveFromContents(address[0], file);
1290 if (iPersistStorage != null) {
1291 iPersistStorage.SaveCompleted(tempStorage.getAddress());
1292 tempStorage.Release();
1293 iPersistStorage.Release();
1298 * Saves the document to the specified file and includes OLE specific information. This method
1299 * must <b>only</b> be used for files that have an OLE Storage format. For example, a word file
1300 * edited with Word.Document should be saved using this method because there is formating information
1301 * that should be stored in the OLE specific Storage format.
1303 * @param file the file to which the changes are to be saved
1305 * @return true if the save was successful
1307 private boolean saveToStorageFile(File file) {
1308 // The file will be saved using the formating of the current application - this
1309 // may not be the format of the application that was originally used to create the file
1310 // e.g. if an Excel file is opened in Word, the Word application will save the file in the
1312 // Note: if the file already exists, some applications will not overwrite the file
1313 // In these cases, you should delete the file first (probably save the contents of the file in case the
1315 if (file == null || file.isDirectory()) return false;
1316 if (!updateStorage()) return false;
1318 // get access to the persistent storage mechanism
1319 long[] address = new long[1];
1320 if (objIOleObject.QueryInterface(COM.IIDIPersistStorage, address) != COM.S_OK) return false;
1321 IPersistStorage permStorage = new IPersistStorage(address[0]);
1323 address = new long[1];
1324 char[] path = (file.getAbsolutePath()+"\0").toCharArray();
1325 int mode = COM.STGM_TRANSACTED | COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
1326 int result = COM.StgCreateDocfile(path, mode, 0, address); //Does an AddRef if successful
1327 if (result != COM.S_OK) return false;
1328 IStorage storage = new IStorage(address[0]);
1330 if (COM.OleSave(permStorage.getAddress(), storage.getAddress(), false) == COM.S_OK) {
1331 if (storage.Commit(COM.STGC_DEFAULT) == COM.S_OK) {
1339 permStorage.Release();
1344 * Saves the document to the specified file. This method must be used for
1345 * files that do not have an OLE Storage format. For example, a bitmap file edited with MSPaint
1346 * should be saved using this method because bitmap is a standard format that does not include any
1347 * OLE specific data.
1349 * @param file the file to which the changes are to be saved
1351 * @return true if the save was successful
1353 private boolean saveToTraditionalFile(File file) {
1354 // Note: if the file already exists, some applications will not overwrite the file
1355 // In these cases, you should delete the file first (probably save the contents of the file in case the
1357 if (file == null || file.isDirectory())
1359 if (!updateStorage())
1362 long[] address = new long[1];
1363 // Look for a CONTENTS stream
1364 if (tempStorage.OpenStream("CONTENTS", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$
1365 return saveFromContents(address[0], file);
1367 // Look for Ole 1.0 object stream
1368 if (tempStorage.OpenStream("\1Ole10Native", 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) //$NON-NLS-1$
1369 return saveFromOle10Native(address[0], file);
1373 private int Scroll(long scrollExtent) {
1376 void setBorderSpace(RECT newBorderwidth) {
1377 borderWidths = newBorderwidth;
1378 // readjust size and location of client site
1382 Rectangle area = DPIUtil.autoScaleUp(frame.getClientArea()); // To Pixels
1383 setBounds(DPIUtil.autoScaleDown(borderWidths.left),
1384 DPIUtil.autoScaleDown(borderWidths.top),
1385 DPIUtil.autoScaleDown(area.width - borderWidths.left - borderWidths.right),
1386 DPIUtil.autoScaleDown(area.height - borderWidths.top - borderWidths.bottom));
1389 private void setExtent(int width, int height){
1390 // Resize the width and height of the embedded/linked OLENatives object
1391 // to the specified values.
1393 if (objIOleObject == null || isStatic || inUpdate) return;
1394 SIZE currentExtent = getExtent();
1395 if (width == currentExtent.cx && height == currentExtent.cy) return;
1397 SIZE newExtent = new SIZE();
1398 newExtent.cx = width; newExtent.cy = height;
1399 newExtent = xFormPixelsToHimetric(newExtent);
1401 // Get the server running first, then do a SetExtent, then show it
1402 boolean alreadyRunning = COM.OleIsRunning(objIOleObject.getAddress());
1403 if (!alreadyRunning)
1404 COM.OleRun(objIOleObject.getAddress());
1406 if (objIOleObject.SetExtent(aspect, newExtent) == COM.S_OK){
1408 objIOleObject.Update();
1410 if (!alreadyRunning)
1411 // Close server if it wasn't already running upon entering this method.
1412 objIOleObject.Close(COM.OLECLOSE_SAVEIFDIRTY);
1416 * The indent value is no longer being used by the client site.
1418 * @param newIndent the rectangle representing the indent amount
1420 public void setIndent(Rectangle newIndent) {
1421 indent = new RECT();
1422 indent.left = newIndent.x;
1423 indent.right = newIndent.width;
1424 indent.top = newIndent.y;
1425 indent.bottom = newIndent.height;
1427 private void setObjectRects() {
1428 if (objIOleInPlaceObject == null) return;
1429 // size the object to fill the available space
1431 RECT rect = getRect();
1432 objIOleInPlaceObject.SetObjectRects(rect, rect);
1435 private int ShowObject() {
1436 /* Tells the container to position the object so it is visible to
1437 * the user. This method ensures that the container itself is
1438 * visible and not minimized.
1444 * Displays a dialog with the property information for this OLE Object. The OLE Document or
1445 * ActiveX Control must support the ISpecifyPropertyPages interface.
1447 * @param title the name that will appear in the titlebar of the dialog
1449 public void showProperties(String title) {
1451 // Get the Property Page information from the OLE Object
1452 long[] ppvObject = new long[1];
1453 if (objIUnknown.QueryInterface(COM.IIDISpecifyPropertyPages, ppvObject) != COM.S_OK) return;
1454 ISpecifyPropertyPages objISPP = new ISpecifyPropertyPages(ppvObject[0]);
1455 CAUUID caGUID = new CAUUID();
1456 int result = objISPP.GetPages(caGUID);
1458 if (result != COM.S_OK) return;
1460 // create a frame in which to display the pages
1461 char[] chTitle = null;
1462 if (title != null) {
1463 chTitle = new char[title.length()];
1464 title.getChars(0, title.length(), chTitle, 0);
1466 result = COM.OleCreatePropertyFrame(frame.handle, 10, 10, chTitle, 1, new long[] {objIUnknown.getAddress()}, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, 0);
1468 // free the property page information
1469 OS.CoTaskMemFree(caGUID.pElems);
1471 private boolean updateStorage() {
1473 if (tempStorage == null) return false;
1475 long[] ppv = new long[1];
1476 if (objIUnknown.QueryInterface(COM.IIDIPersistStorage, ppv) != COM.S_OK) return false;
1477 IPersistStorage iPersistStorage = new IPersistStorage(ppv[0]);
1479 int result = COM.OleSave(iPersistStorage.getAddress(), tempStorage.getAddress(), true);
1481 if (result != COM.S_OK){
1482 // OleSave will fail for static objects, so do what OleSave does.
1483 COM.WriteClassStg(tempStorage.getAddress(), objClsid);
1484 result = iPersistStorage.Save(tempStorage.getAddress(), true);
1487 tempStorage.Commit(COM.STGC_DEFAULT);
1488 result = iPersistStorage.SaveCompleted(0);
1489 iPersistStorage.Release();
1493 private SIZE xFormHimetricToPixels(SIZE aSize) {
1494 // Return a new Size which is the pixel transformation of a
1495 // size in HIMETRIC units.
1497 long hDC = OS.GetDC(0);
1498 int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
1499 int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
1500 OS.ReleaseDC(0, hDC);
1501 int cx = Compatibility.round(aSize.cx * xppi, 2540); // 2540 HIMETRIC units per inch
1502 int cy = Compatibility.round(aSize.cy * yppi, 2540);
1503 SIZE size = new SIZE();
1508 private SIZE xFormPixelsToHimetric(SIZE aSize) {
1509 // Return a new size which is the HIMETRIC transformation of a
1510 // size in pixel units.
1512 long hDC = OS.GetDC(0);
1513 int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
1514 int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
1515 OS.ReleaseDC(0, hDC);
1516 int cx = Compatibility.round(aSize.cx * 2540, xppi); // 2540 HIMETRIC units per inch
1517 int cy = Compatibility.round(aSize.cy * 2540, yppi);
1518 SIZE size = new SIZE();