1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.ole.win32.OleClientSite;
14 
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileOutputStream;
18 import java.lang.all;
19 
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.SWTException;
22 import org.eclipse.swt.graphics.Point;
23 import org.eclipse.swt.graphics.Rectangle;
24 import org.eclipse.swt.internal.Compatibility;
25 // import org.eclipse.swt.internal.ole.win32.CAUUID;
26 // import org.eclipse.swt.internal.ole.win32.COM;
27 // import org.eclipse.swt.internal.ole.win32.COMObject;
28 // import org.eclipse.swt.internal.ole.win32.GUID;
29 // import org.eclipse.swt.internal.ole.win32.IDispatch;
30 // import org.eclipse.swt.internal.ole.win32.IMoniker;
31 // import org.eclipse.swt.internal.ole.win32.IOleCommandTarget;
32 // import org.eclipse.swt.internal.ole.win32.IOleDocument;
33 // import org.eclipse.swt.internal.ole.win32.IOleDocumentView;
34 // import org.eclipse.swt.internal.ole.win32.IOleInPlaceObject;
35 // import org.eclipse.swt.internal.ole.win32.IOleLink;
36 // import org.eclipse.swt.internal.ole.win32.IOleObject;
37 // import org.eclipse.swt.internal.ole.win32.IPersist;
38 // import org.eclipse.swt.internal.ole.win32.IPersistStorage;
39 // import org.eclipse.swt.internal.ole.win32.ISpecifyPropertyPages;
40 // import org.eclipse.swt.internal.ole.win32.IStorage;
41 // import org.eclipse.swt.internal.ole.win32.IStream;
42 // import org.eclipse.swt.internal.ole.win32.IUnknown;
43 // import org.eclipse.swt.internal.ole.win32.IViewObject2;
44 // import org.eclipse.swt.internal.ole.win32.OLECMD;
45 // import org.eclipse.swt.internal.ole.win32.OLEINPLACEFRAMEINFO;
46 import org.eclipse.swt.internal.win32.OS;
47 import org.eclipse.swt.internal.ole.win32.extras;
48 import org.eclipse.swt.internal.ole.win32.OAIDL;
49 import org.eclipse.swt.internal.ole.win32.OLEIDL;
50 import org.eclipse.swt.internal.ole.win32.OBJIDL;
51 import org.eclipse.swt.internal.ole.win32.DOCOBJ;
52 import org.eclipse.swt.internal.ole.win32.COM;
53 import org.eclipse.swt.internal.ole.win32.ifs;
54 
55 import org.eclipse.swt.widgets.Composite;
56 import org.eclipse.swt.widgets.Event;
57 import org.eclipse.swt.widgets.Listener;
58 import org.eclipse.swt.widgets.Menu;
59 import org.eclipse.swt.widgets.Shell;
60 
61 import org.eclipse.swt.ole.win32.OleFrame;
62 import org.eclipse.swt.ole.win32.Variant;
63 import org.eclipse.swt.ole.win32.OLE;
64 
65 
66 /**
67  * OleClientSite provides a site to manage an embedded OLE Document within a container.
68  *
69  * <p>The OleClientSite provides the following capabilities:
70  * <ul>
71  *  <li>creates the in-place editor for a blank document or opening an existing OLE Document
72  *  <li>lays the editor out
73  *  <li>provides a mechanism for activating and deactivating the Document
74  *  <li>provides a mechanism for saving changes made to the document
75  * </ul>
76  *
77  * <p>This object implements the OLE Interfaces IUnknown, IOleClientSite, IAdviseSink,
78  * IOleInPlaceSite
79  *
80  * <p>Note that although this class is a subclass of <code>Composite</code>,
81  * it does not make sense to add <code>Control</code> children to it,
82  * or set a layout on it.
83  * </p><p>
84  * <dl>
85  *  <dt><b>Styles</b> <dd>BORDER
86  *  <dt><b>Events</b> <dd>Dispose, Move, Resize
87  * </dl>
88  *
89  * @see <a href="http://www.eclipse.org/swt/snippets/#ole">OLE and ActiveX snippets</a>
90  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: OLEExample, OleWebBrowser</a>
91  */
92 public class OleClientSite : Composite {
93 
94     // Interfaces for this Ole Client Container
95     private _IUnknownImpl          iUnknown;
96     private _IOleClientSiteImpl    iOleClientSite;
97     private _IAdviseSinkImpl       iAdviseSink;
98     private _IOleInPlaceSiteImpl   iOleInPlaceSite;
99     private _IOleDocumentSiteImpl  iOleDocumentSite;
100 
101     protected GUID* appClsid;
102     private GUID* objClsid;
103     private int  refCount;
104 
105     // References to the associated Frame.
106     package OleFrame frame;
107 
108     // Access to the embedded/linked Ole Object
109     protected IUnknown              objIUnknown;
110     protected IOleObject            objIOleObject;
111     protected IViewObject2          objIViewObject2;
112     protected IOleInPlaceObject     objIOleInPlaceObject;
113     protected IOleCommandTarget     objIOleCommandTarget;
114     protected IOleDocumentView      objDocumentView;
115 
116     // Related storage information
117     protected IStorage tempStorage;     // IStorage interface of the receiver
118 
119     // Internal state and style information
120     private int     aspect;    // the display aspect of the embedded object, e.g., DvaspectContent or DvaspectIcon
121     private int     type;      // Indicates the type of client that can be supported inside this container
122     private bool isStatic;  // Indicates item's display is static, i.e., a bitmap, metafile, etc.
123 
124     private RECT borderWidths;
125     private RECT indent;
126     private bool inUpdate = false;
127     private bool inInit = true;
128     private bool inDispose = false;
129 
130     private static const String WORDPROGID = "Word.Document"; //$NON-NLS-1$
131 
132     private Listener listener;
133 
134     enum{
135         STATE_NONE = 0,
136         STATE_RUNNING = 1,
137         STATE_INPLACEACTIVE = 2,
138         STATE_UIACTIVE = 3,
139         STATE_ACTIVE = 4,
140     }
141     int state = STATE_NONE;
142 
143 protected this(Composite parent, int style) {
144     /*
145      * NOTE: this constructor should never be used by itself because it does
146      * not create an Ole Object
147      */
148     super(parent, style);
149 
150     createCOMInterfaces();
151 
152     // install the Ole Frame for this Client Site
153     while (parent !is null) {
154         if ( auto aframe = cast(OleFrame)parent){
155             frame = aframe;
156             break;
157         }
158         parent = parent.getParent();
159     }
160     if (frame is null) OLE.error (__FILE__, __LINE__, SWT.ERROR_INVALID_ARGUMENT);
161     frame.AddRef();
162 
163     aspect   = COM.DVASPECT_CONTENT;
164     type     = COM.OLEEMBEDDED;
165     isStatic = false;
166 
167     listener = new class() Listener {
168         public void handleEvent(Event e) {
169             switch (e.type) {
170             case SWT.Resize :
171             case SWT.Move :    onResize(e); break;
172             case SWT.Dispose : onDispose(e); break;
173             case SWT.FocusIn:  onFocusIn(e); break;
174             case SWT.FocusOut:  onFocusOut(e); break;
175             case SWT.Paint:    onPaint(e); break;
176             case SWT.Traverse: onTraverse(e); break;
177             case SWT.KeyDown: /* required for traversal */ break;
178             default :
179                 OLE.error (__FILE__, __LINE__, SWT.ERROR_NOT_IMPLEMENTED);
180             }
181         }
182     };
183 
184     frame.addListener(SWT.Resize, listener);
185     frame.addListener(SWT.Move, listener);
186     addListener(SWT.Dispose, listener);
187     addListener(SWT.FocusIn, listener);
188     addListener(SWT.FocusOut, listener);
189     addListener(SWT.Paint, listener);
190     addListener(SWT.Traverse, listener);
191     addListener(SWT.KeyDown, listener);
192 }
193 /**
194  * Create an OleClientSite child widget using the OLE Document type associated with the
195  * specified file.  The OLE Document type is determined either through header information in the file
196  * or through a Registry entry for the file extension. Use style bits to select a particular look
197  * or set of properties.
198  *
199  * @param parent a composite widget; must be an OleFrame
200  * @param style the bitwise OR'ing of widget styles
201  * @param file the file that is to be opened in this OLE Document
202  *
203  * @exception IllegalArgumentException
204  * <ul><li>ERROR_NULL_ARGUMENT when the parent is null
205  *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame</ul>
206  * @exception SWTException
207  * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
208  *     <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
209  *     <li>ERROR_CANNOT_OPEN_FILE when failed to open file
210  *     <li>ERROR_INTERFACE_NOT_FOUND when unable to create callbacks for OLE Interfaces
211  *     <li>ERROR_INVALID_CLASSID
212  * </ul>
213  */
214 public this(Composite parent, int style, File file) {
215     this(parent, style);
216     try {
217 
218         if (file is null || file.isDirectory() || !file.exists())
219             OLE.error (__FILE__, __LINE__, OLE.ERROR_INVALID_ARGUMENT);
220 
221         // Is there an associated CLSID?
222         appClsid = new GUID();
223         LPCTSTR fileName = StrToTCHARz( 0, file.getAbsolutePath() );
224         int result = COM.GetClassFile(fileName, appClsid);
225         if (result !is COM.S_OK)
226             OLE.error (__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID, result);
227         // associated CLSID may not be installed on this machine
228         if (getProgramID() is null)
229             OLE.error (__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID, result);
230 
231         // Open a temporary storage object
232         tempStorage = createTempStorage();
233 
234         // Create ole object with storage object
235         result = COM.OleCreateFromFile(appClsid, fileName, &COM.IIDIUnknown, COM.OLERENDER_DRAW, null, null, tempStorage, cast(void**)&objIUnknown);
236         if (result !is COM.S_OK)
237             OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
238 
239         // Init sinks
240         addObjectReferences();
241 
242         if (COM.OleRun(objIUnknown) is OLE.S_OK) state = STATE_RUNNING;
243     } catch (SWTException e) {
244         dispose();
245         disposeCOMInterfaces();
246         throw e;
247     }
248 }
249 /**
250  * Create an OleClientSite child widget to edit a blank document using the specified OLE Document
251  * application.  Use style bits to select a particular look or set of properties.
252  *
253  * @param parent a composite widget; must be an OleFrame
254  * @param style the bitwise OR'ing of widget styles
255  * @param progId the unique program identifier of am OLE Document application;
256  *               the value of the ProgID key or the value of the VersionIndependentProgID key specified
257  *               in the registry for the desired OLE Document (for example, the VersionIndependentProgID
258  *               for Word is Word.Document)
259  *
260  * @exception IllegalArgumentException
261  *<ul>
262  *     <li>ERROR_NULL_ARGUMENT when the parent is null
263  *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame
264  *</ul>
265  * @exception SWTException
266  * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
267  *     <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
268  *     <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
269  * </ul>
270  */
271 public this(Composite parent, int style, String progId) {
272     this(parent, style);
273     try {
274         appClsid = getClassID(progId);
275         if (appClsid is null)
276             OLE.error (__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID);
277 
278         // Open a temporary storage object
279         tempStorage = createTempStorage();
280 
281         // Create ole object with storage object
282         HRESULT result = COM.OleCreate(appClsid, &COM.IIDIUnknown, COM.OLERENDER_DRAW, null, null, tempStorage, cast(void**)&objIUnknown);
283         if (result !is COM.S_OK)
284             OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
285 
286         // Init sinks
287         addObjectReferences();
288 
289         if (COM.OleRun(objIUnknown) is OLE.S_OK) state = STATE_RUNNING;
290 
291     } catch (SWTException e) {
292         dispose();
293         disposeCOMInterfaces();
294         throw e;
295     }
296 }
297 /**
298  * Create an OleClientSite child widget to edit the specified file using the specified OLE Document
299  * application.  Use style bits to select a particular look or set of properties.
300  * <p>
301  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
302  * API for <code>OleClientSite</code>. It is marked public only so that it
303  * can be shared within the packages provided by SWT. It is not
304  * available on all platforms, and should never be called from
305  * application code.
306  * </p>
307  * @param parent a composite widget; must be an OleFrame
308  * @param style the bitwise OR'ing of widget styles
309  * @param progId the unique program identifier of am OLE Document application;
310  *               the value of the ProgID key or the value of the VersionIndependentProgID key specified
311  *               in the registry for the desired OLE Document (for example, the VersionIndependentProgID
312  *               for Word is Word.Document)
313  * @param file the file that is to be opened in this OLE Document
314  *
315  * @exception IllegalArgumentException
316  * <ul><li>ERROR_NULL_ARGUMENT when the parent is null
317  *     <li>ERROR_INVALID_ARGUMENT when the parent is not an OleFrame</ul>
318  * @exception SWTException
319  * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
320  *     <li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
321  *     <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
322  *     <li>ERROR_CANNOT_OPEN_FILE when failed to open file
323  * </ul>
324  */
325 public this(Composite parent, int style, String progId, File file) {
326     this(parent, style);
327     try {
328         if (file is null || file.isDirectory() || !file.exists()) OLE.error (__FILE__, __LINE__, OLE.ERROR_INVALID_ARGUMENT);
329         appClsid = getClassID(progId);
330         if (appClsid is null) OLE.error (__FILE__, __LINE__, OLE.ERROR_INVALID_CLASSID);
331 
332         // Are we opening this file with the preferred OLE object?
333         LPCTSTR fileName = StrToWCHARz(file.getAbsolutePath());
334         GUID* fileClsid = new GUID();
335         COM.GetClassFile(fileName, fileClsid);
336 
337         if (COM.IsEqualGUID(appClsid, fileClsid)){
338             // Using the same application that created file, therefore, use default mechanism.
339             tempStorage = createTempStorage();
340             // Create ole object with storage object
341             HRESULT result = COM.OleCreateFromFile(appClsid, fileName, &COM.IIDIUnknown, COM.OLERENDER_DRAW, null, null, tempStorage, cast(void**)&objIUnknown);
342             if (result !is COM.S_OK) OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
343         } else {
344             // Not using the same application that created file, therefore, copy from original file to a new storage file
345             IStorage storage = null;
346             if (COM.StgIsStorageFile(fileName) is COM.S_OK) {
347                 int mode = COM.STGM_READ | COM.STGM_TRANSACTED | COM.STGM_SHARE_EXCLUSIVE;
348                 HRESULT result = COM.StgOpenStorage(fileName, null, mode, null, 0, &storage); //Does an AddRef if successful
349                 if (result !is COM.S_OK) OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
350             } else {
351                 // Original file is not a Storage file so copy contents to a stream in a new storage file
352                 int mode = COM.STGM_READWRITE | COM.STGM_DIRECT | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
353                 HRESULT result = COM.StgCreateDocfile(null, mode | COM.STGM_DELETEONRELEASE, 0, &storage); // Increments ref count if successful
354                 if (result !is COM.S_OK) OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
355                 // Create a stream on the storage object.
356                 // Word does not follow the standard and does not use "CONTENTS" as the name of
357                 // its primary stream
358                 LPCTSTR streamName = StrToWCHARz("CONTENTS"); //$NON-NLS-1$
359                 GUID* wordGUID = getClassID(WORDPROGID);
360                 if (wordGUID !is null && COM.IsEqualGUID(appClsid, wordGUID)) streamName = StrToWCHARz("WordDocument"); //$NON-NLS-1$
361                 IStream stream;
362                 result = storage.CreateStream(streamName, mode, 0, 0, &stream); // Increments ref count if successful
363                 if (result !is COM.S_OK) {
364                     storage.Release();
365                     OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
366                 }
367                 try {
368                     // Copy over data in file to named stream
369                     FileInputStream fileInput = new FileInputStream(file);
370                     int increment = 1024*4;
371                     byte[] buffer = new byte[increment];
372                     int count = 0;
373                     while((count = fileInput.read(buffer)) > 0){
374                         auto pv = COM.CoTaskMemAlloc(count);
375                         OS.MoveMemory(pv, buffer.ptr, count);
376                         result = stream.Write(pv, count, null) ;
377                         COM.CoTaskMemFree(pv);
378                         if (result !is COM.S_OK) {
379                             fileInput.close();
380                             stream.Release();
381                             storage.Release();
382                             OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
383                         }
384                     }
385                     fileInput.close();
386                     stream.Commit(COM.STGC_DEFAULT);
387                     stream.Release();
388                 } catch (IOException err) {
389                     stream.Release();
390                     storage.Release();
391                     OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE);
392                 }
393             }
394 
395             // Open a temporary storage object
396             tempStorage = createTempStorage();
397             // Copy over contents of file
398             HRESULT result = storage.CopyTo(0, null, null, tempStorage);
399             storage.Release();
400             if (result !is COM.S_OK) OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_OPEN_FILE, result);
401 
402             // create ole client
403             result = COM.CoCreateInstance(appClsid, null, COM.CLSCTX_INPROC_HANDLER | COM.CLSCTX_INPROC_SERVER, &COM.IIDIUnknown, cast(void**)&objIUnknown);
404             if (result !is COM.S_OK) OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
405             // get the persistent storage of the ole client
406             IPersistStorage iPersistStorage;
407             result = objIUnknown.QueryInterface(&COM.IIDIPersistStorage, cast(void**)&iPersistStorage);
408             if (result !is COM.S_OK) OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
409             // load the contents of the file into the ole client site
410             result = iPersistStorage.Load(tempStorage);
411             iPersistStorage.Release();
412             if (result !is COM.S_OK)OLE.error (__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_OBJECT, result);
413         }
414 
415         // Init sinks
416         addObjectReferences();
417 
418         if (COM.OleRun(objIUnknown) is OLE.S_OK) state = STATE_RUNNING;
419 
420     } catch (SWTException e) {
421         dispose();
422         disposeCOMInterfaces();
423         throw e;
424     }
425 }
426 protected void addObjectReferences() {
427     //
428     IPersist objIPersist;
429     if (objIUnknown.QueryInterface(&COM.IIDIPersist, cast(void**)&objIPersist) is COM.S_OK) {
430         GUID* tempid = new GUID();
431         if (objIPersist.GetClassID(tempid) is COM.S_OK)
432             objClsid = tempid;
433         objIPersist.Release();
434     }
435 
436     //
437     HRESULT result = objIUnknown.QueryInterface(&COM.IIDIViewObject2, cast(void**)&objIViewObject2);
438     if (result !is COM.S_OK)
439         OLE.error (__FILE__, __LINE__, OLE.ERROR_INTERFACE_NOT_FOUND, result);
440     objIViewObject2.SetAdvise(aspect, 0, iAdviseSink);
441 
442     //
443     result = objIUnknown.QueryInterface(&COM.IIDIOleObject, cast(void**)&objIOleObject);
444     if (result !is COM.S_OK)
445         OLE.error (__FILE__, __LINE__, OLE.ERROR_INTERFACE_NOT_FOUND, result);
446     objIOleObject.SetClientSite(iOleClientSite);
447     uint pdwConnection;
448     objIOleObject.Advise(iAdviseSink, &pdwConnection);
449     objIOleObject.SetHostNames("main", "main");  //$NON-NLS-1$ //$NON-NLS-2$
450 
451     // Notify the control object that it is embedded in an OLE container
452     COM.OleSetContainedObject(objIUnknown, true);
453 
454     // Is OLE object linked or embedded?
455     IOleLink objIOleLink;
456     if (objIUnknown.QueryInterface(&COM.IIDIOleLink, cast(void**)&objIOleLink) is COM.S_OK) {
457         IMoniker objIMoniker;
458         if (objIOleLink.GetSourceMoniker(&objIMoniker) is COM.S_OK) {
459             objIMoniker.Release();
460             type = COM.OLELINKED;
461             objIOleLink.BindIfRunning();
462         } else {
463             isStatic = true;
464         }
465         objIOleLink.Release();
466     }
467 }
468 protected int AddRef() {
469     refCount++;
470     return refCount;
471 }
472 private int CanInPlaceActivate() {
473     if (aspect is COM.DVASPECT_CONTENT && type is COM.OLEEMBEDDED)
474         return COM.S_OK;
475 
476     return COM.S_FALSE;
477 }
478 private int ContextSensitiveHelp(int fEnterMode) {
479     return COM.S_OK;
480 }
481 protected void createCOMInterfaces() {
482     iUnknown = new _IUnknownImpl(this);
483     iOleClientSite = new _IOleClientSiteImpl(this);
484     iAdviseSink = new _IAdviseSinkImpl(this);
485     iOleInPlaceSite = new _IOleInPlaceSiteImpl(this);
486     iOleDocumentSite = new _IOleDocumentSiteImpl(this);
487 }
488 protected IStorage createTempStorage() {
489     IStorage tmpStorage;
490     int grfMode = COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_DELETEONRELEASE;
491     HRESULT result = COM.StgCreateDocfile(null, grfMode, 0, &tmpStorage);
492     if (result !is COM.S_OK) OLE.error(__FILE__, __LINE__, OLE.ERROR_CANNOT_CREATE_FILE, result);
493     return (tmpStorage);
494 }
495 /**
496  * Deactivates an active in-place object and discards the object's undo state.
497  */
498 public void deactivateInPlaceClient() {
499     if (objIOleInPlaceObject !is null) {
500         objIOleInPlaceObject.InPlaceDeactivate();
501     }
502 }
503 private void deleteTempStorage() {
504     //Destroy this item's contents in the temp root IStorage.
505     if (tempStorage !is null){
506         tempStorage.Release();
507     }
508     tempStorage = null;
509 }
510 protected void disposeCOMInterfaces() {
511     iUnknown = null;
512     iOleClientSite = null;
513     iAdviseSink = null;
514     iOleInPlaceSite = null;
515     iOleDocumentSite = null;
516 }
517 /**
518  * Requests that the OLE Document or ActiveX Control perform an action; actions are almost always
519  * changes to the activation state.
520  *
521  * @param verb the operation that is requested.  This is one of the OLE.OLEIVERB_ values
522  *
523  * @return an HRESULT value indicating the success of the operation request; OLE.S_OK indicates
524  *         success
525  */
526 public int doVerb(int verb) {
527     // Not all OLE clients (for example PowerPoint) can be set into the running state in the constructor.
528     // The fix is to ensure that the client is in the running state before invoking any verb on it.
529     if (state is STATE_NONE) {
530         if (COM.OleRun(objIUnknown) is OLE.S_OK) state = STATE_RUNNING;
531     }
532     if (state is STATE_NONE || isStatic)
533         return COM.E_FAIL;
534 
535     // See PR: 1FV9RZW
536     RECT rect;
537     OS.GetClientRect(handle, &rect);
538     int result = objIOleObject.DoVerb(verb, null, iOleClientSite, 0, handle, &rect);
539 
540     if (state !is STATE_RUNNING && inInit) {
541         updateStorage();
542         inInit = false;
543     }
544     return result;
545 }
546 /**
547  * Asks the OLE Document or ActiveX Control to execute a command from a standard
548  * list of commands. The OLE Document or ActiveX Control must support the IOleCommandTarget
549  * interface.  The OLE Document or ActiveX Control does not have to support all the commands
550  * in the standard list.  To check if a command is supported, you can call queryStatus with
551  * the cmdID.
552  *
553  * @param cmdID the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
554  *              commands
555  * @param options the optional flags; these are the OLE.OLECMDEXECOPT_ values
556  * @param in the argument for the command
557  * @param out the return value of the command
558  *
559  * @return an HRESULT value; OLE.S_OK is returned if successful
560  *
561  */
562 public int exec(int cmdID, int options, Variant pvaIn, Variant pvaOut) {
563 
564     if (objIOleCommandTarget is null) {
565         if (objIUnknown.QueryInterface(&COM.IIDIOleCommandTarget, cast(void**)&objIOleCommandTarget) !is COM.S_OK)
566             return OLE.ERROR_INTERFACE_NOT_FOUND;
567     }
568 
569     VARIANT* pIn = null;
570     VARIANT* pOut = null;
571 
572     if(pvaIn){
573         pIn = new VARIANT();
574         pvaIn.getData(pIn);
575     }
576     if(pvaOut){
577         pOut = new VARIANT();
578         pvaOut.getData(pOut);
579     }
580 
581     HRESULT result = objIOleCommandTarget.Exec(null, cmdID, options, pIn, pOut);
582 
583     if(pIn) {
584         COM.VariantClear(pIn);
585     }
586 
587     if(pOut) {
588         pvaOut.setData(pOut);
589         COM.VariantClear(pOut);
590     }
591 
592     return result;
593 }
594 IDispatch getAutomationObject() {
595     IDispatch ppvObject;
596     if (objIUnknown.QueryInterface(&COM.IIDIDispatch, cast(void**)&ppvObject) !is COM.S_OK)
597         return null;
598     return ppvObject;
599 }
600 protected GUID* getClassID(String clientName) {
601     // create a GUID struct to hold the result
602     GUID* guid = new GUID();
603 
604     // create a null terminated array of char
605     LPCTSTR buffer = null;
606     if (clientName !is null) {
607         buffer = StrToWCHARz(clientName);
608     }
609     if (COM.CLSIDFromProgID(buffer, guid) !is COM.S_OK){
610         HRESULT result = COM.CLSIDFromString(buffer, guid);
611         if (result !is COM.S_OK) return null;
612     }
613     return guid;
614 }
615 
616 private HRESULT GetContainer(IOleContainer* ppContainer) {
617     /* Simple containers that do not support links to their embedded
618      * objects probably do not need to implement this method. Instead,
619      * they can return E_NOINTERFACE and set ppContainer to NULL.
620      */
621     if (ppContainer !is null)
622         *ppContainer = null;
623     return COM.E_NOINTERFACE;
624 }
625 
626 private SIZE* getExtent() {
627     SIZE* sizel = new SIZE();
628     // get the current size of the embedded OLENatives object
629     if (objIOleObject !is null) {
630         if ( objIViewObject2 !is null && !COM.OleIsRunning(objIOleObject)) {
631             objIViewObject2.GetExtent(aspect, -1, null, sizel);
632         } else {
633             objIOleObject.GetExtent(aspect, sizel);
634         }
635     }
636     return xFormHimetricToPixels(sizel);
637 }
638 /**
639  * Returns the indent value that would be used to compute the clipping area
640  * of the active X object.
641  * 
642  * NOTE: The indent value is no longer being used by the client site.
643  * 
644  * @return the rectangle representing the indent
645  */
646 public Rectangle getIndent() {
647     return new Rectangle(indent.left, indent.right, indent.top, indent.bottom);
648 }
649 /**
650  * Returns the program ID of the OLE Document or ActiveX Control.
651  *
652  * @return the program ID of the OLE Document or ActiveX Control
653  */
654 public String getProgramID(){
655     if (appClsid !is null){
656         wchar* hMem;
657         if (COM.ProgIDFromCLSID(appClsid, &hMem) is COM.S_OK) {
658             auto length = OS.GlobalSize(hMem);
659             auto ptr = OS.GlobalLock(hMem);
660             wchar[] buffer = new wchar[length];
661             COM.MoveMemory(buffer.ptr, ptr, length);
662             OS.GlobalUnlock(hMem);
663             OS.GlobalFree(hMem);
664 
665             String result = WCHARzToStr(buffer.ptr);
666             // remove null terminator
667             //int index = result.indexOf("\0");
668             return result;//.substring(0, index);
669         }
670     }
671     return null;
672 }
673 int ActivateMe(IOleDocumentView pViewToActivate) {
674     if (pViewToActivate is null) {
675         void* ppvObject;
676         if (objIUnknown.QueryInterface(&COM.IIDIOleDocument, &ppvObject) !is COM.S_OK) return COM.E_FAIL;
677         IOleDocument objOleDocument = cast(IOleDocument)ppvObject;
678         if (objOleDocument.CreateView(iOleInPlaceSite, null, 0, &objDocumentView) !is COM.S_OK) return COM.E_FAIL;
679         objOleDocument.Release();
680     } else {
681         objDocumentView = pViewToActivate;
682         objDocumentView.AddRef();
683         objDocumentView.SetInPlaceSite(iOleInPlaceSite);
684     }
685     objDocumentView.UIActivate(1);//TRUE
686     RECT* rect = getRect();
687     objDocumentView.SetRect(rect);
688     objDocumentView.Show(1);//TRUE
689     return COM.S_OK;
690 }
691 protected HRESULT GetWindow(HWND* phwnd) {
692     if (phwnd is null)
693         return COM.E_INVALIDARG;
694     if (frame is null) {
695         *phwnd = null;
696         return COM.E_NOTIMPL;
697     }
698 
699     // Copy the Window's handle into the memory passed in
700     *phwnd = frame.handle;
701     return COM.S_OK;
702 }
703 RECT* getRect() {
704     Point location = this.getLocation();
705     Rectangle area = frame.getClientArea();
706     RECT* rect = new RECT();
707     rect.left   = location.x;
708     rect.top    = location.y;
709     rect.right  = location.x + area.width - borderWidths.left - borderWidths.right;
710     rect.bottom = location.y + area.height - borderWidths.top - borderWidths.bottom;
711     return rect;
712 }
713 
714 private int GetWindowContext(IOleInPlaceFrame* ppFrame, IOleInPlaceUIWindow* ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) {
715     if (frame is null || ppFrame is null)
716         return COM.E_NOTIMPL;
717 
718     // fill in frame handle
719     auto iOleInPlaceFrame = frame.getIOleInPlaceFrame();
720     *ppFrame = iOleInPlaceFrame;
721     frame.AddRef();
722 
723     // null out document handle
724     if (ppDoc !is null) *ppDoc = null;
725 
726     // fill in position and clipping info
727     RECT* rect = getRect();
728     if (lprcPosRect !is null) OS.MoveMemory(lprcPosRect, rect, RECT.sizeof);
729     if (lprcClipRect !is null) OS.MoveMemory(lprcClipRect, rect, RECT.sizeof);
730 
731     // get frame info
732     OLEINPLACEFRAMEINFO* frameInfo = new OLEINPLACEFRAMEINFO();
733     frameInfo.cb = OLEINPLACEFRAMEINFO.sizeof;
734     frameInfo.fMDIApp = 0;
735     frameInfo.hwndFrame = frame.handle;
736     Shell shell = getShell();
737     Menu menubar = shell.getMenuBar();
738     if (menubar !is null && !menubar.isDisposed()) {
739         auto hwnd = shell.handle;
740         auto cAccel = cast(uint)/*64bit*/OS.SendMessage(hwnd, OS.WM_APP, 0, 0);
741         if (cAccel !is 0) {
742             auto hAccel = cast(HACCEL) OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
743             if (hAccel !is null) {
744                 frameInfo.cAccelEntries = cAccel;
745                 frameInfo.haccel = hAccel;
746             }
747         }
748     }
749     COM.MoveMemory(lpFrameInfo, frameInfo, OLEINPLACEFRAMEINFO.sizeof);
750 
751     return COM.S_OK;
752 }
753 /**
754  * Returns whether ole document is dirty by checking whether the content 
755  * of the file representing the document is dirty.
756  * 
757  * @return <code>true</code> if the document has been modified,
758  *         <code>false</code> otherwise.
759  * @since 3.1
760  */
761 public bool isDirty() {
762     /*
763      *  Note: this method must return true unless it is absolutely clear that the
764      * contents of the Ole Document do not differ from the contents in the file
765      * on the file system.
766      */
767 
768     // Get access to the persistent storage mechanism
769     IPersistStorage permStorage;
770     if (objIOleObject.QueryInterface(&COM.IIDIPersistFile, cast(void**)&permStorage) !is COM.S_OK)
771         return true;
772     // Are the contents of the permanent storage different from the file?
773     auto result = permStorage.IsDirty();
774     permStorage.Release();
775     if (result is COM.S_FALSE) return false;
776     return true;
777 }
778 override
779 public bool isFocusControl () {
780     checkWidget ();
781     auto focusHwnd = OS.GetFocus();
782     if (objIOleInPlaceObject is null) return (handle is focusHwnd);
783     HWND phwnd;
784     objIOleInPlaceObject.GetWindow(&phwnd);
785     while (focusHwnd !is null) {
786         if (phwnd is focusHwnd) return true;
787         focusHwnd = OS.GetParent(focusHwnd);
788     }
789     return false;
790 }
791 private int OnClose() {
792     return COM.S_OK;
793 }
794 private int OnDataChange(int pFormatetc, int pStgmed) {
795     return COM.S_OK;
796 }
797 private void onDispose(Event e) {
798     inDispose = true;
799     if (state !is STATE_NONE)
800         doVerb(OLE.OLEIVERB_DISCARDUNDOSTATE);
801     deactivateInPlaceClient();
802     releaseObjectInterfaces(); // Note, must release object interfaces before releasing frame
803     deleteTempStorage();
804 
805     // remove listeners
806     removeListener(SWT.Dispose, listener);
807     removeListener(SWT.FocusIn, listener);
808     removeListener(SWT.Paint, listener);
809     removeListener(SWT.Traverse, listener);
810     removeListener(SWT.KeyDown, listener);
811     frame.removeListener(SWT.Resize, listener);
812     frame.removeListener(SWT.Move, listener);
813 
814     frame.Release();
815     frame = null;
816 }
817 void onFocusIn(Event e) {
818     if (inDispose) return;
819     if (state !is STATE_UIACTIVE) doVerb(OLE.OLEIVERB_SHOW);
820     if (objIOleInPlaceObject is null) return;
821     if (isFocusControl()) return;
822     HWND phwnd;
823     objIOleInPlaceObject.GetWindow(&phwnd);
824     if (phwnd is null) return;
825     OS.SetFocus(phwnd);
826 }
827 void onFocusOut(Event e) {
828 }
829 private int OnInPlaceActivate() {
830     state = STATE_INPLACEACTIVE;
831     frame.setCurrentDocument(this);
832     if (objIOleObject is null)
833         return COM.S_OK;
834     int[] ppvObject = new int[1];
835     if (objIOleObject.QueryInterface(&COM.IIDIOleInPlaceObject, cast(void**)&objIOleInPlaceObject) is COM.S_OK) {
836         //objIOleInPlaceObject = new IOleInPlaceObject(ppvObject[0]);
837     }
838     return COM.S_OK;
839 }
840 private int OnInPlaceDeactivate() {
841     if (objIOleInPlaceObject !is null) objIOleInPlaceObject.Release();
842     objIOleInPlaceObject = null;
843     state = STATE_RUNNING;
844     redraw();
845     Shell shell = getShell();
846     if (isFocusControl() || frame.isFocusControl()) {
847         shell.traverse(SWT.TRAVERSE_TAB_NEXT);
848     }
849     return COM.S_OK;
850 }
851 private int OnPosRectChange(LPRECT lprcPosRect) {
852     Point size = getSize();
853     setExtent(size.x, size.y);
854     return COM.S_OK;
855 }
856 private void onPaint(Event e) {
857     if (state is STATE_RUNNING || state is STATE_INPLACEACTIVE) {
858         SIZE* size = getExtent();
859         Rectangle area = getClientArea();
860         RECT* rect = new RECT();
861         if (getProgramID().startsWith("Excel.Sheet")) { //$NON-NLS-1$
862             rect.left = area.x; rect.right = area.x + (area.height * size.cx / size.cy);
863             rect.top = area.y; rect.bottom = area.y + area.height;
864         } else {
865             rect.left = area.x; rect.right = area.x + size.cx;
866             rect.top = area.y; rect.bottom = area.y + size.cy;
867         }
868 
869         auto pArea = cast(RECT*)OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, RECT.sizeof);
870         OS.MoveMemory(pArea, rect, RECT.sizeof);
871         COM.OleDraw(objIUnknown, aspect, e.gc.handle, pArea);
872         OS.GlobalFree(pArea);
873     }
874 }
875 private void onResize(Event e) {
876     Rectangle area = frame.getClientArea();
877     setBounds(borderWidths.left,
878               borderWidths.top,
879               area.width - borderWidths.left - borderWidths.right,
880               area.height - borderWidths.top - borderWidths.bottom);
881 
882     setObjectRects();
883 }
884 private void OnSave() {
885 }
886 private int OnShowWindow(int fShow) {
887     return COM.S_OK;
888 }
889 private int OnUIActivate() {
890     if (objIOleInPlaceObject is null) return COM.E_FAIL;
891     state = STATE_UIACTIVE;
892     HWND phwnd;
893     if (objIOleInPlaceObject.GetWindow(&phwnd) is COM.S_OK) {
894         OS.SetWindowPos(phwnd, cast(HWND)OS.HWND_TOP, 0, 0, 0, 0, OS.SWP_NOSIZE | OS.SWP_NOMOVE);
895     }
896     return COM.S_OK;
897 }
898 private int OnUIDeactivate(int fUndoable) {
899     // currently, we are ignoring the fUndoable flag
900     if (frame is null || frame.isDisposed()) return COM.S_OK;
901     state = STATE_INPLACEACTIVE;
902     frame.SetActiveObject(null, null);
903     redraw();
904     Shell shell = getShell();
905     if (isFocusControl() || frame.isFocusControl()) {
906         shell.traverse(SWT.TRAVERSE_TAB_NEXT);
907     }
908     Menu menubar = shell.getMenuBar();
909     if (menubar is null || menubar.isDisposed())
910         return COM.S_OK;
911 
912     auto shellHandle = shell.handle;
913     OS.SetMenu(shellHandle, menubar.handle);
914     return COM.OleSetMenuDescriptor(null, shellHandle, null, null, null);
915 }
916 private void onTraverse(Event event) {
917     switch (event.detail) {
918         case SWT.TRAVERSE_ESCAPE:
919         case SWT.TRAVERSE_RETURN:
920         case SWT.TRAVERSE_TAB_NEXT:
921         case SWT.TRAVERSE_TAB_PREVIOUS:
922         case SWT.TRAVERSE_PAGE_NEXT:
923         case SWT.TRAVERSE_PAGE_PREVIOUS:
924         case SWT.TRAVERSE_MNEMONIC:
925             event.doit = true;
926             break;
927         default:
928     }
929 }
930 private int OnViewChange(int dwAspect, int lindex) {
931     return COM.S_OK;
932 }
933 protected HRESULT QueryInterface(REFCIID riid, void ** ppvObject) {
934 
935     if (riid is null || ppvObject is null)
936         return COM.E_NOINTERFACE;
937     GUID oGuid = *riid;
938     GUID* guid = &oGuid;
939     //COM.MoveMemory(guid, riid, GUID.sizeof);
940 
941     if (COM.IsEqualGUID(guid, &COM.IIDIUnknown)) {
942         *ppvObject = cast(void*)cast(IUnknown)iUnknown;
943         AddRef();
944         return COM.S_OK;
945     }
946     if (COM.IsEqualGUID(guid, &COM.IIDIAdviseSink)) {
947         *ppvObject = cast(void*)cast(IAdviseSink)iAdviseSink;
948         AddRef();
949         return COM.S_OK;
950     }
951     if (COM.IsEqualGUID(guid, &COM.IIDIOleClientSite)) {
952         *ppvObject = cast(void*)cast(IOleClientSite)iOleClientSite;
953         AddRef();
954         return COM.S_OK;
955     }
956     if (COM.IsEqualGUID(guid, &COM.IIDIOleInPlaceSite)) {
957         *ppvObject = cast(void*)cast(IOleInPlaceSite)iOleInPlaceSite;
958         AddRef();
959         return COM.S_OK;
960     }
961     if (COM.IsEqualGUID(guid, &COM.IIDIOleDocumentSite )) {
962         String progID = getProgramID();
963         if (!progID.startsWith("PowerPoint")) { //$NON-NLS-1$
964             *ppvObject = cast(void*)cast(IOleDocumentSite)iOleDocumentSite;
965             AddRef();
966             return COM.S_OK;
967         }
968     }
969     *ppvObject = null;
970     return COM.E_NOINTERFACE;
971 }
972 /**
973  * Returns the status of the specified command.  The status is any bitwise OR'd combination of
974  * SWTOLE.OLECMDF_SUPPORTED, SWTOLE.OLECMDF_ENABLED, SWTOLE.OLECMDF_LATCHED, SWTOLE.OLECMDF_NINCHED.
975  * You can query the status of a command before invoking it with OleClientSite.exec.  The
976  * OLE Document or ActiveX Control must support the IOleCommandTarget to make use of this method.
977  *
978  * @param cmd the ID of a command; these are the OLE.OLECMDID_ values - a small set of common
979  *            commands
980  *
981  * @return the status of the specified command or 0 if unable to query the OLE Object; these are the
982  *            OLE.OLECMDF_ values
983  */
984 public int queryStatus(int cmd) {
985 
986     if (objIOleCommandTarget is null) {
987         if (objIUnknown.QueryInterface(&COM.IIDIOleCommandTarget, cast(void**)&objIOleCommandTarget) !is COM.S_OK)
988             return 0;
989     }
990 
991     OLECMD* olecmd = new OLECMD();
992     olecmd.cmdID = cmd;
993 
994     auto result = objIOleCommandTarget.QueryStatus(null, 1, olecmd, null);
995 
996     if (result !is COM.S_OK) return 0;
997 
998     return olecmd.cmdf;
999 }
1000 protected int Release() {
1001     refCount--;
1002 
1003     if (refCount is 0) {
1004         disposeCOMInterfaces();
1005     }
1006     return refCount;
1007 }
1008 protected void releaseObjectInterfaces() {
1009 
1010     if (objIOleInPlaceObject !is null)
1011         objIOleInPlaceObject.Release();
1012     objIOleInPlaceObject = null;
1013 
1014     if (objIOleObject !is null) {
1015         objIOleObject.Close(COM.OLECLOSE_NOSAVE);
1016         objIOleObject.Release();
1017     }
1018     objIOleObject = null;
1019 
1020     if (objDocumentView !is null){
1021         objDocumentView.Release();
1022     }
1023     objDocumentView = null;
1024 
1025     if (objIViewObject2 !is null) {
1026         objIViewObject2.SetAdvise(aspect, 0, null);
1027         objIViewObject2.Release();
1028     }
1029     objIViewObject2 = null;
1030 
1031     if (objIOleCommandTarget !is null)
1032         objIOleCommandTarget.Release();
1033     objIOleCommandTarget = null;
1034 
1035     if (objIUnknown !is null){
1036         objIUnknown.Release();
1037     }
1038     objIUnknown = null;
1039 
1040     COM.CoFreeUnusedLibraries();
1041 }
1042 /**
1043  * Saves the document to the specified file and includes OLE specific information if specified.  
1044  * This method must <b>only</b> be used for files that have an OLE Storage format.  For example, 
1045  * a word file edited with Word.Document should be saved using this method because there is 
1046  * formating information that should be stored in the OLE specific Storage format.
1047  *
1048  * @param file the file to which the changes are to be saved
1049  * @param includeOleInfo the flag to indicate whether OLE specific information should be saved.
1050  *
1051  * @return true if the save was successful
1052  */
1053 public bool save(File file, bool includeOleInfo) {
1054     if (includeOleInfo)
1055         return saveToStorageFile(file);
1056     return saveToTraditionalFile(file);
1057 }
1058 private bool saveFromContents(IStream address, File file) {
1059 
1060     bool success = false;
1061 
1062     IStream tempContents = address;
1063     tempContents.AddRef();
1064 
1065     try {
1066         FileOutputStream writer = new FileOutputStream(file);
1067 
1068         int increment = 1024 * 4;
1069         LPVOID pv = COM.CoTaskMemAlloc(increment);
1070         uint pcbWritten;
1071         while (tempContents.Read(pv, increment, &pcbWritten) is COM.S_OK && pcbWritten > 0) {
1072             byte[] buffer = new byte[ pcbWritten];
1073             OS.MoveMemory(buffer.ptr, pv, pcbWritten);
1074             writer.write(buffer); // Note: if file does not exist, this will create the file the
1075                                   // first time it is called
1076             success = true;
1077         }
1078         COM.CoTaskMemFree(pv);
1079 
1080         writer.close();
1081 
1082     } catch (IOException err) {
1083     }
1084 
1085     tempContents.Release();
1086 
1087     return success;
1088 }
1089 private bool saveFromOle10Native(IStream address, File file) {
1090 
1091     bool success = false;
1092 
1093     IStream tempContents = address;
1094     tempContents.AddRef();
1095 
1096     // The "\1Ole10Native" stream contains a DWORD header whose value is the length
1097     // of the native data that follows.
1098     LPVOID pv = COM.CoTaskMemAlloc(4);
1099     uint size;
1100     auto rc = tempContents.Read(pv, 4, null);
1101     OS.MoveMemory(&size, pv, 4);
1102     COM.CoTaskMemFree(pv);
1103     if (rc is COM.S_OK && size > 0) {
1104 
1105         // Read the data
1106         byte[] buffer = new byte[size];
1107         pv = COM.CoTaskMemAlloc(size);
1108         rc = tempContents.Read(pv, size, null);
1109         OS.MoveMemory(buffer.ptr, pv, size);
1110         COM.CoTaskMemFree(pv);
1111 
1112         // open the file and write data into it
1113         try {
1114             FileOutputStream writer = new FileOutputStream(file);
1115             writer.write(buffer); // Note: if file does not exist, this will create the file
1116             writer.close();
1117 
1118             success = true;
1119         } catch (IOException err) {
1120         }
1121     }
1122     tempContents.Release();
1123 
1124     return success;
1125 }
1126 private int SaveObject() {
1127 
1128     updateStorage();
1129 
1130     return COM.S_OK;
1131 }
1132 /**
1133  * Saves the document to the specified file and includes OLE specific information.  This method
1134  * must <b>only</b> be used for files that have an OLE Storage format.  For example, a word file
1135  * edited with Word.Document should be saved using this method because there is formating information
1136  * that should be stored in the OLE specific Storage format.
1137  *
1138  * @param file the file to which the changes are to be saved
1139  *
1140  * @return true if the save was successful
1141  */
1142 private bool saveToStorageFile(File file) {
1143     // The file will be saved using the formating of the current application - this
1144     // may not be the format of the application that was originally used to create the file
1145     // e.g. if an Excel file is opened in Word, the Word application will save the file in the
1146     // Word format
1147     // Note: if the file already exists, some applications will not overwrite the file
1148     // In these cases, you should delete the file first (probably save the contents of the file in case the
1149     // save fails)
1150     if (file is null || file.isDirectory()) return false;
1151     if (!updateStorage()) return false;
1152 
1153     // get access to the persistent storage mechanism
1154     IPersistStorage permStorage;
1155     if (objIOleObject.QueryInterface(&COM.IIDIPersistStorage, cast(void**)&permStorage) !is COM.S_OK) return false;
1156     try {
1157         IStorage storage;
1158         LPCTSTR path = StrToWCHARz(file.getAbsolutePath());
1159         int mode = COM.STGM_TRANSACTED | COM.STGM_READWRITE | COM.STGM_SHARE_EXCLUSIVE | COM.STGM_CREATE;
1160         int result = COM.StgCreateDocfile(path, mode, 0, &storage); //Does an AddRef if successful
1161         if (result !is COM.S_OK) return false;
1162         try {
1163             if (COM.OleSave(permStorage, storage, false) is COM.S_OK) {
1164                 if (storage.Commit(COM.STGC_DEFAULT) is COM.S_OK) {
1165                     return true;
1166                 }
1167             }
1168         } finally {
1169             storage.Release();
1170         }
1171     } finally {
1172         permStorage.Release();
1173     }
1174     return false;
1175 }
1176 /**
1177  * Saves the document to the specified file.  This method must be used for
1178  * files that do not have an OLE Storage format.  For example, a bitmap file edited with MSPaint
1179  * should be saved using this method because bitmap is a standard format that does not include any
1180  * OLE specific data.
1181  *
1182  * @param file the file to which the changes are to be saved
1183  *
1184  * @return true if the save was successful
1185  */
1186 private bool saveToTraditionalFile(File file) {
1187     // Note: if the file already exists, some applications will not overwrite the file
1188     // In these cases, you should delete the file first (probably save the contents of the file in case the
1189     // save fails)
1190     if (file is null || file.isDirectory())
1191         return false;
1192     if (!updateStorage())
1193         return false;
1194 
1195     IStream stream;
1196     // Look for a CONTENTS stream
1197     if (tempStorage.OpenStream(("CONTENTS"w).ptr, null, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, &stream) is COM.S_OK) //$NON-NLS-1$
1198         return saveFromContents(stream, file);
1199 
1200     // Look for Ole 1.0 object stream
1201     if (tempStorage.OpenStream(("\1Ole10Native"w).ptr, null, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, &stream) is COM.S_OK) //$NON-NLS-1$
1202         return saveFromOle10Native(stream, file);
1203 
1204     return false;
1205 }
1206 private int Scroll(int scrollExtant) {
1207     return COM.S_OK;
1208 }
1209 void setBorderSpace(RECT* newBorderwidth) {
1210     borderWidths = *newBorderwidth;
1211     // readjust size and location of client site
1212     Rectangle area = frame.getClientArea();
1213     setBounds(borderWidths.left, borderWidths.top,
1214                 area.width - borderWidths.left - borderWidths.right,
1215                 area.height - borderWidths.top - borderWidths.bottom);
1216     setObjectRects();
1217 }
1218 private void setExtent(int width, int height){
1219     // Resize the width and height of the embedded/linked OLENatives object
1220     // to the specified values.
1221 
1222     if (objIOleObject is null || isStatic || inUpdate) return;
1223     SIZE* currentExtent = getExtent();
1224     if (width is currentExtent.cx && height is currentExtent.cy) return;
1225 
1226     SIZE* newExtent = new SIZE();
1227     newExtent.cx = width; newExtent.cy = height;
1228     newExtent = xFormPixelsToHimetric(newExtent);
1229 
1230    // Get the server running first, then do a SetExtent, then show it
1231     bool alreadyRunning = cast(bool) COM.OleIsRunning(objIOleObject);
1232     if (!alreadyRunning)
1233         COM.OleRun(objIOleObject);
1234 
1235     if (objIOleObject.SetExtent(aspect, newExtent) is COM.S_OK){
1236         inUpdate = true;
1237         objIOleObject.Update();
1238         inUpdate = false;
1239         if (!alreadyRunning)
1240             // Close server if it wasn't already running upon entering this method.
1241             objIOleObject.Close(COM.OLECLOSE_SAVEIFDIRTY);
1242     }
1243 }
1244 /**
1245  * The indent value is no longer being used by the client site.
1246  * 
1247  * @param newIndent the rectangle representing the indent amount
1248  */
1249 public void setIndent(Rectangle newIndent) {
1250     indent.left = newIndent.x;
1251     indent.right = newIndent.width;
1252     indent.top = newIndent.y;
1253     indent.bottom = newIndent.height;
1254 }
1255 private void setObjectRects() {
1256     if (objIOleInPlaceObject is null) return;
1257     // size the object to fill the available space
1258     // leave a border
1259     RECT* rect = getRect();
1260     objIOleInPlaceObject.SetObjectRects(rect, rect);
1261 }
1262 
1263 private int ShowObject() {
1264     /* Tells the container to position the object so it is visible to
1265      * the user. This method ensures that the container itself is
1266      * visible and not minimized.
1267      */
1268     return COM.S_OK;
1269 }
1270 /**
1271  * Displays a dialog with the property information for this OLE Object.  The OLE Document or
1272  * ActiveX Control must support the ISpecifyPropertyPages interface.
1273  *
1274  * @param title the name that will appear in the titlebar of the dialog
1275  */
1276 public void showProperties(String title) {
1277 
1278     // Get the Property Page information from the OLE Object
1279     ISpecifyPropertyPages objISPP;
1280     if (objIUnknown.QueryInterface(&COM.IIDISpecifyPropertyPages, cast(void**)&objISPP) !is COM.S_OK) return;
1281     CAUUID* caGUID = new CAUUID();
1282     auto result = objISPP.GetPages(caGUID);
1283     objISPP.Release();
1284     if (result !is COM.S_OK) return;
1285 
1286     // create a frame in which to display the pages
1287     LPCTSTR chTitle = null;
1288     if (title !is null) {
1289         chTitle = StrToWCHARz(title);
1290     }
1291     result = COM.OleCreatePropertyFrame(frame.handle, 10, 10, chTitle, 1, &objIUnknown, caGUID.cElems, caGUID.pElems, COM.LOCALE_USER_DEFAULT, 0, null);
1292 
1293     // free the property page information
1294     COM.CoTaskMemFree(caGUID.pElems);
1295 }
1296 private bool updateStorage() {
1297 
1298     if (tempStorage is null) return false;
1299 
1300     IPersistStorage iPersistStorage;
1301     if (objIUnknown.QueryInterface(&COM.IIDIPersistStorage, cast(void**)&iPersistStorage) !is COM.S_OK) return false;
1302 
1303     auto result = COM.OleSave(iPersistStorage, tempStorage, true);
1304 
1305     if (result !is COM.S_OK){
1306         // OleSave will fail for static objects, so do what OleSave does.
1307         COM.WriteClassStg(tempStorage, objClsid);
1308         result = iPersistStorage.Save(tempStorage, true);
1309     }
1310 
1311     tempStorage.Commit(COM.STGC_DEFAULT);
1312     result = iPersistStorage.SaveCompleted(null);
1313     iPersistStorage.Release();
1314 
1315     return true;
1316 }
1317 private SIZE* xFormHimetricToPixels(SIZE* aSize) {
1318     // Return a new Size which is the pixel transformation of a
1319     // size in HIMETRIC units.
1320 
1321     auto hDC = OS.GetDC(null);
1322     int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
1323     int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
1324     OS.ReleaseDC(null, hDC);
1325     int cx = Compatibility.round(aSize.cx * xppi, 2540); // 2540 HIMETRIC units per inch
1326     int cy = Compatibility.round(aSize.cy * yppi, 2540);
1327     SIZE* size = new SIZE();
1328     size.cx = cx;
1329     size.cy = cy;
1330     return size;
1331 }
1332 private SIZE* xFormPixelsToHimetric(SIZE* aSize) {
1333     // Return a new size which is the HIMETRIC transformation of a
1334     // size in pixel units.
1335 
1336     auto hDC = OS.GetDC(null);
1337     int xppi = OS.GetDeviceCaps(hDC, 88); // logical pixels/inch in x
1338     int yppi = OS.GetDeviceCaps(hDC, 90); // logical pixels/inch in y
1339     OS.ReleaseDC(null, hDC);
1340     int cx = Compatibility.round(aSize.cx * 2540, xppi); // 2540 HIMETRIC units per inch
1341     int cy = Compatibility.round(aSize.cy * 2540, yppi);
1342     SIZE* size = new SIZE();
1343     size.cx = cx;
1344     size.cy = cy;
1345     return size;
1346 }
1347 }
1348 
1349 class _IAdviseSinkImpl : IAdviseSink {
1350 
1351     OleClientSite   parent;
1352     this(OleClientSite  p) { parent = p; }
1353 extern (Windows):
1354     // interface of IUnknown
1355     HRESULT QueryInterface(REFCIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
1356     ULONG AddRef()  { return parent.AddRef(); }
1357     ULONG Release() { return parent.Release(); }
1358 
1359     // interface of IAdviseSink
1360     void OnDataChange(FORMATETC *pFormatetc,STGMEDIUM *pStgmed) { }
1361     void OnViewChange(DWORD dwAspect, LONG lindex) { }
1362     void OnRename(IMoniker pmk) { }
1363     void OnSave() { }
1364     void OnClose() { }
1365 }
1366 
1367 class _IOleClientSiteImpl : IOleClientSite {
1368 
1369     OleClientSite   parent;
1370     this(OleClientSite  p) { parent = p; }
1371 extern (Windows):
1372     // interface of IUnknown
1373     HRESULT QueryInterface(REFCIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
1374     ULONG AddRef()  { return parent.AddRef(); }
1375     ULONG Release() { return parent.Release(); }
1376 
1377     // interface of IOleClientSite
1378     HRESULT SaveObject() {  if(parent) parent.updateStorage(); return COM.S_OK; }
1379     HRESULT GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker, IMoniker * ppmk ) {return COM.E_NOTIMPL; }
1380     HRESULT GetContainer( IOleContainer* ppContainer ) { return parent.GetContainer(ppContainer);}
1381     HRESULT ShowObject() {
1382         /* Tells the container to position the object so it is visible to
1383          * the user. This method ensures that the container itself is
1384          * visible and not minimized.
1385          */
1386         return COM.S_OK;
1387     }
1388     HRESULT OnShowWindow(BOOL fShow ) {return COM.S_OK; }
1389     HRESULT RequestNewObjectLayout() {return COM.E_NOTIMPL; }
1390 }
1391 
1392 class  _IOleDocumentSiteImpl : IOleDocumentSite {
1393 
1394     OleClientSite   parent;
1395     this(OleClientSite  p) { parent = p; }
1396 extern (Windows):
1397     // interface of IUnknown
1398     HRESULT QueryInterface(REFCIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
1399     ULONG AddRef()  { return parent.AddRef(); }
1400     ULONG Release() { return parent.Release(); }
1401 
1402     // interface of IOleDocumentSite
1403     HRESULT ActivateMe(IOleDocumentView pViewToActivate) { return parent.ActivateMe(pViewToActivate);}
1404 }
1405 
1406 class _IOleInPlaceSiteImpl : IOleInPlaceSite {
1407     OleClientSite   parent;
1408     this(OleClientSite  p) { parent = p; }
1409 extern (Windows):
1410     // interface of IUnknown
1411     HRESULT QueryInterface(REFCIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
1412     ULONG AddRef()  { return parent.AddRef(); }
1413     ULONG Release() { return parent.Release(); }
1414 
1415     // interface of IOleWindow
1416     HRESULT GetWindow( HWND*  phwnd ) { return parent.GetWindow(phwnd); }
1417     HRESULT ContextSensitiveHelp( BOOL fEnterMode ) {return COM.S_OK; }
1418 
1419     // interface of IOleInPlaceSite
1420     HRESULT CanInPlaceActivate() { return parent.CanInPlaceActivate();}
1421     HRESULT OnInPlaceActivate() { return parent.OnInPlaceActivate(); }
1422     HRESULT OnUIActivate() { return parent.OnUIActivate(); }
1423     HRESULT GetWindowContext( IOleInPlaceFrame * ppFrame, IOleInPlaceUIWindow * ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo ) {
1424         return parent.GetWindowContext(ppFrame, ppDoc, lprcPosRect, lprcClipRect, lpFrameInfo);
1425     }
1426     HRESULT Scroll( SIZE scrollExtant ) {return COM.S_OK; }
1427     HRESULT OnUIDeactivate( BOOL fUndoable ) { return parent.OnUIDeactivate(fUndoable);}
1428     HRESULT OnInPlaceDeactivate() { return parent.OnInPlaceDeactivate();}
1429     HRESULT DiscardUndoState() {return COM.E_NOTIMPL; }
1430     HRESULT DeactivateAndUndo() {return COM.E_NOTIMPL; }
1431     HRESULT OnPosRectChange( LPCRECT lprcPosRect) { return parent.OnPosRectChange(lprcPosRect);}
1432 }
1433 
1434 class _IUnknownImpl : IUnknown
1435 {
1436 
1437     OleClientSite   parent;
1438     this(OleClientSite  p) { parent = p; }
1439 extern (Windows):
1440     // interface of IUnknown
1441     HRESULT QueryInterface(REFCIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
1442     ULONG AddRef()  { return parent.AddRef(); }
1443     ULONG Release() { return parent.Release(); }
1444 }
1445 
1446 
1447 
1448