]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleClientSite.java
Work around SWT 4.13 - 4.18 Win32 DnD bug 567422
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / ole / win32 / OleClientSite.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 IBM Corporation and others.
3  *
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/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.ole.win32;
15
16 import java.io.*;
17
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.*;
24 /**
25  * OleClientSite provides a site to manage an embedded OLE Document within a container.
26  *
27  * <p>The OleClientSite provides the following capabilities:
28  * <ul>
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
33  * </ul>
34  *
35  * <p>This object implements the OLE Interfaces IUnknown, IOleClientSite, IAdviseSink,
36  * IOleInPlaceSite
37  *
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.
41  * </p>
42  * <dl>
43  *      <dt><b>Styles</b> <dd>BORDER
44  *      <dt><b>Events</b> <dd>Dispose, Move, Resize
45  * </dl>
46  *
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>
49  */
50 public class OleClientSite extends Composite {
51
52         // Interfaces for this Ole Client Container
53         COMObject  iOleClientSite;
54         private COMObject  iAdviseSink;
55         private COMObject  iOleInPlaceSite;
56         private COMObject  iOleDocumentSite;
57
58         protected GUID appClsid;
59         private GUID objClsid;
60         private int  refCount;
61
62         // References to the associated Frame.
63         protected OleFrame frame;
64
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;
72
73         // Related storage information
74         protected IStorage tempStorage;     // IStorage interface of the receiver
75
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.
80         boolean isActivated;
81
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;
87
88         private static final String WORDPROGID = "Word.Document"; //$NON-NLS-1$
89
90         private Listener listener;
91
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;
98
99 protected OleClientSite(Composite parent, int style) {
100         /*
101          * NOTE: this constructor should never be used by itself because it does
102          * not create an Ole Object
103          */
104         super(parent, style);
105
106         createCOMInterfaces();
107
108         // install the Ole Frame for this Client Site
109         while (parent != null) {
110                 if (parent instanceof OleFrame){
111                         frame = (OleFrame)parent;
112                         break;
113                 }
114                 parent = parent.getParent();
115         }
116         if (frame == null) OLE.error(SWT.ERROR_INVALID_ARGUMENT);
117         frame.AddRef();
118
119         aspect   = COM.DVASPECT_CONTENT;
120         type     = COM.OLEEMBEDDED;
121         isStatic = false;
122
123         listener = new Listener() {
124                 private int nestedFocusEvents = 0;
125                 @Override
126                 public void handleEvent(Event e) {
127                         switch (e.type) {
128                         case SWT.Resize :
129                         case SWT.Move :    onResize(e); break;
130                         case SWT.Dispose : onDispose(e); break;
131                         case SWT.FocusIn:
132                                 nestedFocusEvents++;
133                                 boolean hasFocus = isFocusControl();
134                                 onFocusIn(e);
135                                 nestedFocusEvents--;
136                                 /*
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
139                                  */
140                                 if (nestedFocusEvents == 0 && hasFocus == isFocusControl())
141                                         frame.onFocusIn(e);
142                                 break;
143                         case SWT.FocusOut:
144                                 nestedFocusEvents++;
145                                 onFocusOut(e);
146                                 nestedFocusEvents--;
147                                 if (nestedFocusEvents == 0)
148                                         frame.onFocusOut(e);
149                                 break;
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;
155                         default :
156                                 OLE.error(SWT.ERROR_NOT_IMPLEMENTED);
157                         }
158                 }
159         };
160
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);
171 }
172 /**
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.
177  *
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
181  *
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
191  * </ul>
192  */
193 public OleClientSite(Composite parent, int style, File file) {
194         this(parent, style);
195         try {
196
197                 if (file == null || file.isDirectory() || !file.exists())
198                         OLE.error(SWT.ERROR_INVALID_ARGUMENT);
199
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);
208
209                 appClsid = fileClsid;
210                 OleCreate(appClsid, fileClsid, fileName, file);
211         } catch (SWTException e) {
212                 dispose();
213                 disposeCOMInterfaces();
214                 throw e;
215         }
216 }
217 /**
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.
220  *
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)
227  *
228  * @exception IllegalArgumentException
229  *<ul>
230  *     <li>ERROR_NULL_ARGUMENT when the parent is null
231  *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
232  *</ul>
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
237  * </ul>
238  */
239 public OleClientSite(Composite parent, int style, String progId) {
240         this(parent, style);
241         try {
242                 appClsid = getClassID(progId);
243                 if (appClsid == null)
244                         OLE.error(OLE.ERROR_INVALID_CLASSID);
245
246                 // Open a temporary storage object
247                 tempStorage = createTempStorage();
248
249                 // Create ole object with storage object
250                 long[] address = new long[1];
251                 /*
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.
256                 */
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);
261
262                 objIUnknown = new IUnknown(address[0]);
263
264                 // Init sinks
265                 addObjectReferences();
266
267                 if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
268
269         } catch (SWTException e) {
270                 dispose();
271                 disposeCOMInterfaces();
272                 throw e;
273         }
274 }
275 /**
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.
278  * <p>
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
283  * application code.
284  * </p>
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
292  *
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
301  * </ul>
302  *
303  * @noreference This method is not intended to be referenced by clients.
304  */
305 public OleClientSite(Composite parent, int style, String progId, File file) {
306         this(parent, style);
307         try {
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);
311
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);
316
317                 OleCreate(appClsid, fileClsid, fileName, file);
318         } catch (SWTException e) {
319                 dispose();
320                 disposeCOMInterfaces();
321                 throw e;
322         }
323 }
324
325 void OleCreate(GUID appClsid, GUID fileClsid, char[] fileName, File file) {
326
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().
332          */
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]);
342         } else {
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]);
351                 } else {
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) {
368                                 storage.Release();
369                                 OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
370                         }
371                         IStream stream = new IStream(address[0]);
372                         try {
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];
377                                 int count = 0;
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) {
384                                                 fileInput.close();
385                                                 stream.Release();
386                                                 storage.Release();
387                                                 OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
388                                         }
389                                 }
390                                 fileInput.close();
391                                 stream.Commit(COM.STGC_DEFAULT);
392                                 stream.Release();
393                         } catch (IOException err) {
394                                 stream.Release();
395                                 storage.Release();
396                                 OLE.error(OLE.ERROR_CANNOT_OPEN_FILE);
397                         }
398                 }
399
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());
404                 storage.Release();
405                 if (result != COM.S_OK) OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
406
407                 // create ole client
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
413                 ppv = new long[1];
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);
421         }
422
423         // Init sinks
424         addObjectReferences();
425
426         if (COM.OleRun(objIUnknown.getAddress()) == OLE.S_OK) state = STATE_RUNNING;
427 }
428 protected void addObjectReferences() {
429         //
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)
435                         objClsid = tempid;
436                 objIPersist.Release();
437         }
438
439         //
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());
446
447         //
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]);
453         /*
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.
459          */
460         long[] ppvClientSite = new long[1];
461         result = objIOleObject.GetClientSite(ppvClientSite);
462         if (ppvClientSite[0] == 0) {
463                 objIOleObject.SetClientSite(iOleClientSite.getAddress());
464         } else {
465                 Release(); // GetClientSite performs an AddRef so we must release it.
466         }
467         int[] pdwConnection = new int[1];
468         objIOleObject.Advise(iAdviseSink.getAddress(), pdwConnection);
469         objIOleObject.SetHostNames("main", "main");  //$NON-NLS-1$ //$NON-NLS-2$
470
471         // Notify the control object that it is embedded in an OLE container
472         COM.OleSetContainedObject(objIUnknown.getAddress(), true);
473
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();
483                 } else {
484                         isStatic = true;
485                 }
486                 objIOleLink.Release();
487         }
488 }
489 protected int AddRef() {
490         refCount++;
491         return refCount;
492 }
493 private int CanInPlaceActivate() {
494         if (aspect == COM.DVASPECT_CONTENT && type == COM.OLEEMBEDDED)
495                 return COM.S_OK;
496
497         return COM.S_FALSE;
498 }
499 private int ContextSensitiveHelp(int fEnterMode) {
500         return COM.S_OK;
501 }
502 protected void createCOMInterfaces() {
503
504         iOleClientSite = new COMObject(new int[]{2, 0, 0, 0, 3, 1, 0, 1, 0}){
505                 @Override
506                 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
507                 @Override
508                 public long method1(long[] args) {return AddRef();}
509                 @Override
510                 public long method2(long[] args) {return Release();}
511                 @Override
512                 public long method3(long[] args) {return SaveObject();}
513                 // method4 GetMoniker - not implemented
514                 @Override
515                 public long method5(long[] args) {return GetContainer(args[0]);}
516                 @Override
517                 public long method6(long[] args) {return ShowObject();}
518                 @Override
519                 public long method7(long[] args) {return OnShowWindow((int)args[0]);}
520                 // method8 RequestNewObjectLayout - not implemented
521         };
522
523         iAdviseSink = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 0, 0}){
524                 @Override
525                 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
526                 @Override
527                 public long method1(long[] args) {return AddRef();}
528                 @Override
529                 public long method2(long[] args) {return Release();}
530                 @Override
531                 public long method3(long[] args) {return OnDataChange(args[0], args[1]);}
532                 @Override
533                 public long method4(long[] args) {return OnViewChange((int)args[0], (int)args[1]);}
534                 //method5 OnRename - not implemented
535                 @Override
536                 public long method6(long[] args) {OnSave();return 0;}
537                 @Override
538                 public long method7(long[] args) {return OnClose();}
539         };
540
541         iOleInPlaceSite = new COMObject(new int[]{2, 0, 0, 1, 1, 0, 0, 0, 5, 1, 1, 0, 0, 0, 1}){
542                 @Override
543                 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
544                 @Override
545                 public long method1(long[] args) {return AddRef();}
546                 @Override
547                 public long method2(long[] args) {return Release();}
548                 @Override
549                 public long method3(long[] args) {return GetWindow(args[0]);}
550                 @Override
551                 public long method4(long[] args) {return ContextSensitiveHelp((int)args[0]);}
552                 @Override
553                 public long method5(long[] args) {return CanInPlaceActivate();}
554                 @Override
555                 public long method6(long[] args) {return OnInPlaceActivate();}
556                 @Override
557                 public long method7(long[] args) {return OnUIActivate();}
558                 @Override
559                 public long method8(long[] args) {return GetWindowContext(args[0], args[1], args[2], args[3], args[4]);}
560                 @Override
561                 public long method9(long[] args) {return Scroll(args[0]);}
562                 @Override
563                 public long method10(long[] args) {return OnUIDeactivate((int)args[0]);}
564                 @Override
565                 public long method11(long[] args) {return OnInPlaceDeactivate();}
566                 // method12 DiscardUndoState - not implemented
567                 // method13 DeactivateAndUndoChange - not implemented
568                 @Override
569                 public long method14(long[] args) {return OnPosRectChange(args[0]);}
570         };
571
572         iOleDocumentSite = new COMObject(new int[]{2, 0, 0, 1}){
573                 @Override
574                 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
575                 @Override
576                 public long method1(long[] args) {return AddRef();}
577                 @Override
578                 public long method2(long[] args) {return Release();}
579                 @Override
580                 public long method3(long[] args) {return ActivateMe(args[0]);}
581         };
582 }
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]);
589 }
590 /**
591  * Deactivates an active in-place object and discards the object's undo state.
592  */
593 public void deactivateInPlaceClient() {
594         if (objIOleInPlaceObject != null) {
595                 objIOleInPlaceObject.InPlaceDeactivate();
596         }
597 }
598 private void deleteTempStorage() {
599         //Destroy this item's contents in the temp root IStorage.
600         if (tempStorage != null){
601                 tempStorage.Release();
602         }
603         tempStorage = null;
604 }
605 protected void disposeCOMInterfaces() {
606         if (iOleClientSite != null)
607                 iOleClientSite.dispose();
608         iOleClientSite = null;
609
610         if (iAdviseSink != null)
611                 iAdviseSink.dispose();
612         iAdviseSink = null;
613
614         if (iOleInPlaceSite != null)
615                 iOleInPlaceSite.dispose();
616         iOleInPlaceSite = null;
617
618         if (iOleDocumentSite != null)
619                 iOleDocumentSite.dispose();
620         iOleDocumentSite = null;
621 }
622 /**
623  * Requests that the OLE Document or ActiveX Control perform an action; actions are almost always
624  * changes to the activation state.
625  *
626  * @param verb the operation that is requested.  This is one of the OLE.OLEIVERB_ values
627  *
628  * @return an HRESULT value indicating the success of the operation request; OLE.S_OK indicates
629  *         success
630  */
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;
636         }
637         if (state == STATE_NONE || isStatic)
638                 return COM.E_FAIL;
639
640         // See PR: 1FV9RZW
641         RECT rect = new RECT();
642         OS.GetClientRect(handle, rect);
643         int result = objIOleObject.DoVerb(verb, null, iOleClientSite.getAddress(), 0, handle, rect);
644
645         if (state != STATE_RUNNING && inInit) {
646                 updateStorage();
647                 inInit = false;
648         }
649         return result;
650 }
651 /**
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
656  * the cmdID.
657  *
658  * @param cmdID the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
659  *              commands
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
663  *
664  * @return an HRESULT value; OLE.S_OK is returned if successful
665  *
666  */
667 public int exec(int cmdID, int options, Variant in, Variant out) {
668
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]);
674         }
675
676         long inAddress = 0;
677         if (in != null){
678                 inAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
679                 in.getData(inAddress);
680         }
681         long outAddress = 0;
682         if (out != null){
683                 outAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
684                 out.getData(outAddress);
685         }
686
687         int result = objIOleCommandTarget.Exec(null, cmdID, options, inAddress, outAddress);
688
689         if (inAddress != 0){
690                 COM.VariantClear(inAddress);
691                 OS.GlobalFree(inAddress);
692         }
693         if (outAddress != 0) {
694                 out.setData(outAddress);
695                 COM.VariantClear(outAddress);
696                 OS.GlobalFree(outAddress);
697         }
698
699         return result;
700 }
701 IDispatch getAutomationObject() {
702         long[] ppvObject = new long[1];
703         if (objIUnknown.QueryInterface(COM.IIDIDispatch, ppvObject) != COM.S_OK)
704                 return null;
705         return new IDispatch(ppvObject[0]);
706 }
707 protected GUID getClassID(String clientName) {
708         // create a GUID struct to hold the result
709         GUID guid = new GUID();
710
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);
717         }
718         if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){
719                 int result = COM.CLSIDFromString(buffer, guid);
720                 if (result != COM.S_OK) return null;
721         }
722         return guid;
723 }
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.
728          */
729         if (ppContainer != 0)
730                 OS.MoveMemory(ppContainer, new long[]{0}, C.PTR_SIZEOF);
731         return COM.E_NOINTERFACE;
732 }
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);
739                 } else {
740                         objIOleObject.GetExtent(aspect, sizel);
741                 }
742         }
743         return xFormHimetricToPixels(sizel);
744 }
745 /**
746  * Returns the indent value that would be used to compute the clipping area
747  * of the active X object.
748  *
749  * NOTE: The indent value is no longer being used by the client site.
750  *
751  * @return the rectangle representing the indent
752  */
753 public Rectangle getIndent() {
754         return new Rectangle(indent.left, indent.right, indent.top, indent.bottom);
755 }
756 /**
757  * Returns the program ID of the OLE Document or ActiveX Control.
758  *
759  * @return the program ID of the OLE Document or ActiveX Control
760  */
761 public String getProgramID(){
762         return getProgID(appClsid);
763 }
764 String getProgID(GUID clsid) {
765         if (clsid != null){
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);
774                         OS.GlobalFree(hMem);
775
776                         String result = new String(buffer);
777                         // remove null terminator
778                         int index = result.indexOf("\0");
779                         return result.substring(0, index);
780                 }
781         }
782         return null;
783 }
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]);
792         } else {
793                 objDocumentView = new IOleDocumentView(pViewToActivate);
794                 objDocumentView.AddRef();
795                 objDocumentView.SetInPlaceSite(iOleInPlaceSite.getAddress());
796         }
797         objDocumentView.UIActivate(1);//TRUE
798         RECT rect = getRect();
799         objDocumentView.SetRect(rect);
800         objDocumentView.Show(1);//TRUE
801         return COM.S_OK;
802 }
803 protected int GetWindow(long phwnd) {
804         if (phwnd == 0)
805                 return COM.E_INVALIDARG;
806         if (frame == null) {
807                 OS.MoveMemory(phwnd, new long[] {0}, C.PTR_SIZEOF);
808                 return COM.E_NOTIMPL;
809         }
810
811         // Copy the Window's handle into the memory passed in
812         OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF);
813         return COM.S_OK;
814 }
815 RECT getRect() {
816         Rectangle area = DPIUtil.autoScaleUp(getClientArea()); // To Pixels
817         RECT rect = new RECT();
818         rect.left   = area.x;
819         rect.top    = area.y;
820         rect.right  = area.x + area.width;
821         rect.bottom = area.y + area.height;
822         return rect;
823 }
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;
827
828         // fill in frame handle
829         long iOleInPlaceFrame = frame.getIOleInPlaceFrame();
830         OS.MoveMemory(ppFrame, new long[] {iOleInPlaceFrame}, C.PTR_SIZEOF);
831         frame.AddRef();
832
833         // null out document handle
834         if (ppDoc != 0) OS.MoveMemory(ppDoc, new long[] {0}, C.PTR_SIZEOF);
835
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);
840
841         // get frame info
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);
851                 if (cAccel != 0) {
852                         long hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
853                         if (hAccel != 0) {
854                                 frameInfo.cAccelEntries = cAccel;
855                                 frameInfo.haccel = hAccel;
856                         }
857                 }
858         }
859         COM.MoveMemory(lpFrameInfo, frameInfo, OLEINPLACEFRAMEINFO.sizeof);
860
861         return COM.S_OK;
862 }
863 boolean isICAClient() {
864         return getProgramID().startsWith("Citrix.ICAClient"); //$NON-NLS-1$
865 }
866 /**
867  * Returns whether ole document is dirty by checking whether the content
868  * of the file representing the document is dirty.
869  *
870  * @return <code>true</code> if the document has been modified,
871  *         <code>false</code> otherwise.
872  * @since 3.1
873  */
874 public boolean isDirty() {
875         /*
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.
879          */
880
881         // Get access to the persistent storage mechanism
882         long[] address = new long[1];
883         if (objIOleObject.QueryInterface(COM.IIDIPersistFile, address) != COM.S_OK)
884                 return true;
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;
890         return true;
891 }
892 @Override
893 public boolean isFocusControl () {
894         checkWidget ();
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);
902         }
903         return false;
904 }
905 private boolean isOffice2007(boolean program) {
906         String programID = getProgramID();
907         if (programID == null) return false;
908         if (program) {
909                 int lastDot = programID.lastIndexOf('.');
910                 if (lastDot != -1) {
911                         programID = programID.substring(0, lastDot);
912                         GUID guid = getClassID(programID);
913                         programID = getProgID(guid);
914                         if (programID == null) return false;
915                 }
916         }
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$
920         return false;
921 }
922 private int OnClose() {
923         return COM.S_OK;
924 }
925 private int OnDataChange(long pFormatetc, long pStgmed) {
926         return COM.S_OK;
927 }
928 private void onDispose(Event e) {
929         inDispose = true;
930
931         // remove listeners
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);
938
939         if (state != STATE_NONE)
940                 doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE);
941         deactivateInPlaceClient();
942         releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame
943         deleteTempStorage();
944
945         frame.removeListener(SWT.Resize, listener);
946         frame.removeListener(SWT.Move, listener);
947
948         frame.Release();
949         frame = null;
950 }
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);
959                 }
960         }
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]);
967 }
968 void onFocusOut(Event e) {
969 }
970 private int OnInPlaceActivate() {
971         state = STATE_INPLACEACTIVE;
972         frame.setCurrentDocument(this);
973         if (objIOleObject == null)
974                 return COM.S_OK;
975         long[] ppvObject = new long[1];
976         if (objIOleObject.QueryInterface(COM.IIDIOleInPlaceObject, ppvObject) == COM.S_OK) {
977                 objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]);
978         }
979         return COM.S_OK;
980 }
981 private int OnInPlaceDeactivate() {
982         if (objIOleInPlaceObject != null) objIOleInPlaceObject.Release();
983         objIOleInPlaceObject = null;
984         state = STATE_RUNNING;
985         redraw();
986         Shell shell = getShell();
987         if (isFocusControl() || frame.isFocusControl()) {
988                 shell.traverse(SWT.TRAVERSE_TAB_NEXT);
989         }
990         return COM.S_OK;
991 }
992 private int OnPosRectChange(long lprcPosRect) {
993         Point size = DPIUtil.autoScaleUp(getSize()); // To Pixels
994         setExtent(size.x, size.y);
995         return COM.S_OK;
996 }
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;
1005                 } else {
1006                         rect.left = area.x; rect.right = area.x + size.cx;
1007                         rect.top = area.y; rect.bottom = area.y + size.cy;
1008                 }
1009
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);
1014         }
1015 }
1016 private void onResize(Event e) {
1017         setBounds();
1018 }
1019 private void OnSave() {
1020 }
1021 private int OnShowWindow(int fShow) {
1022         return COM.S_OK;
1023 }
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);
1030         }
1031         return COM.S_OK;
1032 }
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);
1038         redraw();
1039         Shell shell = getShell();
1040         if (isFocusControl() || frame.isFocusControl()) {
1041                 shell.traverse(SWT.TRAVERSE_TAB_NEXT);
1042         }
1043         Menu menubar = shell.getMenuBar();
1044         if (menubar == null || menubar.isDisposed())
1045                 return COM.S_OK;
1046
1047         long shellHandle = shell.handle;
1048         OS.SetMenu(shellHandle, menubar.handle);
1049         return COM.OleSetMenuDescriptor(0, shellHandle, 0, 0, 0);
1050 }
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:
1060                         event.doit = true;
1061                         break;
1062         }
1063 }
1064 private int OnViewChange(int dwAspect, int lindex) {
1065         return COM.S_OK;
1066 }
1067 protected int QueryInterface(long riid, long ppvObject) {
1068
1069         if (riid == 0 || ppvObject == 0)
1070                 return COM.E_NOINTERFACE;
1071         GUID guid = new GUID();
1072         COM.MoveMemory(guid, riid, GUID.sizeof);
1073
1074         if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIOleClientSite)) {
1075                 OS.MoveMemory(ppvObject, new long[] {iOleClientSite.getAddress()}, C.PTR_SIZEOF);
1076                 AddRef();
1077                 return COM.S_OK;
1078         }
1079         if (COM.IsEqualGUID(guid, COM.IIDIAdviseSink)) {
1080                 OS.MoveMemory(ppvObject, new long[] {iAdviseSink.getAddress()}, C.PTR_SIZEOF);
1081                 AddRef();
1082                 return COM.S_OK;
1083         }
1084         if (COM.IsEqualGUID(guid, COM.IIDIOleInPlaceSite)) {
1085                 OS.MoveMemory(ppvObject, new long[] {iOleInPlaceSite.getAddress()}, C.PTR_SIZEOF);
1086                 AddRef();
1087                 return COM.S_OK;
1088         }
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);
1093                         AddRef();
1094                         return COM.S_OK;
1095                 }
1096         }
1097         OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
1098         return COM.E_NOINTERFACE;
1099 }
1100 /**
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.
1105  *
1106  * @param cmd the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
1107  *            commands
1108  *
1109  * @return the status of the specified command or 0 if unable to query the OLE Object; these are the
1110  *                        OLE.OLECMDF_ values
1111  */
1112 public int queryStatus(int cmd) {
1113
1114         if (objIOleCommandTarget == null) {
1115                 long[] address = new long[1];
1116                 if (objIUnknown.QueryInterface(COM.IIDIOleCommandTarget, address) != COM.S_OK)
1117                         return 0;
1118                 objIOleCommandTarget = new IOleCommandTarget(address[0]);
1119         }
1120
1121         OLECMD olecmd = new OLECMD();
1122         olecmd.cmdID = cmd;
1123
1124         int result = objIOleCommandTarget.QueryStatus(null, 1, olecmd, 0);
1125
1126         if (result != COM.S_OK) return 0;
1127
1128         return olecmd.cmdf;
1129 }
1130 protected int Release() {
1131         refCount--;
1132
1133         if (refCount == 0) {
1134                 disposeCOMInterfaces();
1135         }
1136         return refCount;
1137 }
1138 protected void releaseObjectInterfaces() {
1139
1140         if (objIOleInPlaceObject!= null)
1141                 objIOleInPlaceObject.Release();
1142         objIOleInPlaceObject = null;
1143
1144         if (objIOleObject != null) {
1145                 objIOleObject.Close(COM.OLECLOSE_NOSAVE);
1146                 objIOleObject.Release();
1147         }
1148         objIOleObject = null;
1149
1150         if (objDocumentView != null){
1151                 objDocumentView.Release();
1152         }
1153         objDocumentView = null;
1154
1155         if (objIViewObject2 != null) {
1156                 objIViewObject2.SetAdvise(aspect, 0, 0);
1157                 objIViewObject2.Release();
1158         }
1159         objIViewObject2 = null;
1160
1161         if (objIOleCommandTarget != null)
1162                 objIOleCommandTarget.Release();
1163         objIOleCommandTarget = null;
1164
1165         if (objIUnknown != null){
1166                 objIUnknown.Release();
1167         }
1168         objIUnknown = null;
1169
1170         if (COM.FreeUnusedLibraries) {
1171                 COM.CoFreeUnusedLibraries();
1172         }
1173 }
1174 /**
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.
1179  *
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.
1182  *
1183  * @return true if the save was successful
1184  */
1185 public boolean save(File file, boolean includeOleInfo) {
1186         /*
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.
1190         */
1191         if (isOffice2007(false)) {
1192                 return saveOffice2007(file);
1193         }
1194         if (includeOleInfo)
1195                 return saveToStorageFile(file);
1196         return saveToTraditionalFile(file);
1197 }
1198 private boolean saveFromContents(long address, File file) {
1199
1200         boolean success = false;
1201
1202         IStream tempContents = new IStream(address);
1203         tempContents.AddRef();
1204
1205         try {
1206                 FileOutputStream writer = new FileOutputStream(file);
1207
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
1216                         success = true;
1217                 }
1218                 OS.CoTaskMemFree(pv);
1219
1220                 writer.close();
1221
1222         } catch (IOException err) {
1223         }
1224
1225         tempContents.Release();
1226
1227         return success;
1228 }
1229 private boolean saveFromOle10Native(long address, File file) {
1230
1231         boolean success = false;
1232
1233         IStream tempContents = new IStream(address);
1234         tempContents.AddRef();
1235
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) {
1244
1245                 // Read the data
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);
1251
1252                 // open the file and write data into it
1253                 try {
1254                         FileOutputStream writer = new FileOutputStream(file);
1255                         writer.write(buffer); // Note: if file does not exist, this will create the file
1256                         writer.close();
1257
1258                         success = true;
1259                 } catch (IOException err) {
1260                 }
1261         }
1262         tempContents.Release();
1263
1264         return success;
1265 }
1266 private int SaveObject() {
1267
1268         updateStorage();
1269
1270         return COM.S_OK;
1271 }
1272 private boolean saveOffice2007(File file) {
1273         if (file == null || file.isDirectory()) return false;
1274         if (!updateStorage()) return false;
1275         boolean result = false;
1276
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();
1284         }
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);
1289         }
1290         if (iPersistStorage != null) {
1291                 iPersistStorage.SaveCompleted(tempStorage.getAddress());
1292                 tempStorage.Release();
1293                 iPersistStorage.Release();
1294         }
1295         return result;
1296 }
1297 /**
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.
1302  *
1303  * @param file the file to which the changes are to be saved
1304  *
1305  * @return true if the save was successful
1306  */
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
1311         // Word format
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
1314         // save fails)
1315         if (file == null || file.isDirectory()) return false;
1316         if (!updateStorage()) return false;
1317
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]);
1322         try {
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]);
1329                 try {
1330                         if (COM.OleSave(permStorage.getAddress(), storage.getAddress(), false) == COM.S_OK) {
1331                                 if (storage.Commit(COM.STGC_DEFAULT) == COM.S_OK) {
1332                                         return true;
1333                                 }
1334                         }
1335                 } finally {
1336                         storage.Release();
1337                 }
1338         } finally {
1339                 permStorage.Release();
1340         }
1341         return false;
1342 }
1343 /**
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.
1348  *
1349  * @param file the file to which the changes are to be saved
1350  *
1351  * @return true if the save was successful
1352  */
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
1356         // save fails)
1357         if (file == null || file.isDirectory())
1358                 return false;
1359         if (!updateStorage())
1360                 return false;
1361
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);
1366
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);
1370
1371         return false;
1372 }
1373 private int Scroll(long scrollExtent) {
1374         return COM.S_OK;
1375 }
1376 void setBorderSpace(RECT newBorderwidth) {
1377         borderWidths = newBorderwidth;
1378         // readjust size and location of client site
1379         setBounds();
1380 }
1381 void setBounds() {
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));
1387         setObjectRects();
1388 }
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.
1392
1393         if (objIOleObject == null || isStatic || inUpdate) return;
1394         SIZE currentExtent = getExtent();
1395         if (width == currentExtent.cx && height == currentExtent.cy) return;
1396
1397         SIZE newExtent = new SIZE();
1398         newExtent.cx = width; newExtent.cy = height;
1399         newExtent = xFormPixelsToHimetric(newExtent);
1400
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());
1405
1406         if (objIOleObject.SetExtent(aspect, newExtent) == COM.S_OK){
1407                 inUpdate = true;
1408                 objIOleObject.Update();
1409                 inUpdate = false;
1410                 if (!alreadyRunning)
1411                         // Close server if it wasn't already running upon entering this method.
1412                         objIOleObject.Close(COM.OLECLOSE_SAVEIFDIRTY);
1413         }
1414 }
1415 /**
1416  * The indent value is no longer being used by the client site.
1417  *
1418  * @param newIndent the rectangle representing the indent amount
1419  */
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;
1426 }
1427 private void setObjectRects() {
1428         if (objIOleInPlaceObject == null) return;
1429         // size the object to fill the available space
1430         // leave a border
1431         RECT rect = getRect();
1432         objIOleInPlaceObject.SetObjectRects(rect, rect);
1433 }
1434
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.
1439          */
1440         setBounds();
1441         return COM.S_OK;
1442 }
1443 /**
1444  * Displays a dialog with the property information for this OLE Object.  The OLE Document or
1445  * ActiveX Control must support the ISpecifyPropertyPages interface.
1446  *
1447  * @param title the name that will appear in the titlebar of the dialog
1448  */
1449 public void showProperties(String title) {
1450
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);
1457         objISPP.Release();
1458         if (result != COM.S_OK) return;
1459
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);
1465         }
1466         result = COM.OleCreatePropertyFrame(frame.handle, 10, 10, chTitle, 1, new long[] {objIUnknown.getAddress()}, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, 0);
1467
1468         // free the property page information
1469         OS.CoTaskMemFree(caGUID.pElems);
1470 }
1471 private boolean updateStorage() {
1472
1473         if (tempStorage == null) return false;
1474
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]);
1478
1479         int result = COM.OleSave(iPersistStorage.getAddress(), tempStorage.getAddress(), true);
1480
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);
1485         }
1486
1487         tempStorage.Commit(COM.STGC_DEFAULT);
1488         result = iPersistStorage.SaveCompleted(0);
1489         iPersistStorage.Release();
1490
1491         return true;
1492 }
1493 private SIZE xFormHimetricToPixels(SIZE aSize) {
1494         // Return a new Size which is the pixel transformation of a
1495         // size in HIMETRIC units.
1496
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();
1504         size.cx = cx;
1505         size.cy = cy;
1506         return size;
1507 }
1508 private SIZE xFormPixelsToHimetric(SIZE aSize) {
1509         // Return a new size which is the HIMETRIC transformation of a
1510         // size in pixel units.
1511
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();
1519         size.cx = cx;
1520         size.cy = cy;
1521         return size;
1522 }
1523 }