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