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.OleFrame; 14 15 import java.util.Vector; 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.SWTException; 19 import org.eclipse.swt.internal.ole.win32.COM; 20 import org.eclipse.swt.internal.ole.win32.OLEIDL; 21 import org.eclipse.swt.internal.ole.win32.extras; 22 import org.eclipse.swt.internal.win32.OS; 23 import org.eclipse.swt.widgets.Composite; 24 import org.eclipse.swt.widgets.Control; 25 import org.eclipse.swt.widgets.Display; 26 import org.eclipse.swt.widgets.Event; 27 import org.eclipse.swt.widgets.Listener; 28 import org.eclipse.swt.widgets.Menu; 29 import org.eclipse.swt.widgets.MenuItem; 30 import org.eclipse.swt.widgets.Shell; 31 import org.eclipse.swt.widgets.Widget; 32 33 import org.eclipse.swt.ole.win32.OleClientSite; 34 import org.eclipse.swt.ole.win32.OLE; 35 36 import org.eclipse.swt.internal.LONG; 37 38 import java.lang.all; 39 import java.lang.Runnable; 40 41 /** 42 * 43 * OleFrame is an OLE Container's top level frame. 44 * 45 * <p>This object implements the OLE Interfaces IUnknown and IOleInPlaceFrame 46 * 47 * <p>OleFrame allows the container to do the following: <ul> 48 * <li>position and size the ActiveX Control or OLE Document within the application 49 * <li>insert menu items from the application into the OLE Document's menu 50 * <li>activate and deactivate the OLE Document's menus 51 * <li>position the OLE Document's menu in the application 52 * <li>translate accelerator keystrokes intended for the container's frame</ul> 53 * 54 * <dl> 55 * <dt><b>Styles</b> <dd>BORDER 56 * <dt><b>Events</b> <dd>Dispose, Move, Resize 57 * </dl> 58 * 59 * @see <a href="http://www.eclipse.org/swt/snippets/#ole">OLE and ActiveX snippets</a> 60 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: OLEExample, OleWebBrowser</a> 61 */ 62 final public class OleFrame : Composite 63 { 64 // Interfaces for this Ole Client Container 65 //private COMObject iUnknown; 66 private _IOleInPlaceFrameImpl iOleInPlaceFrame; 67 68 // Access to the embedded/linked Ole Object 69 private IOleInPlaceActiveObject objIOleInPlaceActiveObject; 70 71 private OleClientSite currentdoc; 72 73 private int refCount = 0; 74 75 private MenuItem[] fileMenuItems; 76 private MenuItem[] containerMenuItems; 77 private MenuItem[] windowMenuItems; 78 79 private Listener listener; 80 81 private static String CHECK_FOCUS = "OLE_CHECK_FOCUS"; //$NON-NLS-1$ 82 private static String HHOOK = "OLE_HHOOK"; //$NON-NLS-1$ 83 private static String HHOOKMSG = "OLE_HHOOK_MSG"; //$NON-NLS-1$ 84 85 private static bool ignoreNextKey; 86 private static const short [] ACCENTS = [ cast(short)'~', '`', '\'', '^', '"']; 87 88 private static const String CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$ 89 90 /** 91 * Create an OleFrame child widget using style bits 92 * to select a particular look or set of properties. 93 * 94 * @param parent a composite widget (cannot be null) 95 * @param style the bitwise OR'ing of widget styles 96 * 97 * @exception IllegalArgumentException <ul> 98 * <li>ERROR_NULL_ARGUMENT when the parent is null 99 * </ul> 100 * @exception SWTException <ul> 101 * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread 102 * </ul> 103 * 104 */ 105 public this(Composite parent, int style) { 106 super(parent, style); 107 108 createCOMInterfaces(); 109 110 // setup cleanup proc 111 listener = new class() Listener { 112 public void handleEvent(Event e) { 113 switch (e.type) { 114 case SWT.Activate : onActivate(e); break; 115 case SWT.Deactivate : onDeactivate(e); break; 116 case SWT.Dispose : onDispose(e); break; 117 case SWT.Resize : 118 case SWT.Move : onResize(e); break; 119 default : 120 OLE.error(SWT.ERROR_NOT_IMPLEMENTED); 121 } 122 } 123 }; 124 125 126 addListener(SWT.Activate, listener); 127 addListener(SWT.Deactivate, listener); 128 addListener(SWT.Dispose, listener); 129 130 // inform inplaceactiveobject whenever frame resizes 131 addListener(SWT.Resize, listener); 132 133 // inform inplaceactiveobject whenever frame moves 134 addListener(SWT.Move, listener); 135 136 // Maintain a reference to yourself so that when 137 // ClientSites close, they don't take the frame away 138 // with them. 139 this.AddRef(); 140 141 // Check for focus change 142 Display display = getDisplay(); 143 initCheckFocus(display); 144 initMsgHook(display); 145 } 146 private static void initCheckFocus (Display display_) { 147 if (display_.getData(CHECK_FOCUS) !is null) return; 148 display_.setData(CHECK_FOCUS, new ArrayWrapperString(CHECK_FOCUS)); 149 static const int time = 50; 150 auto timer = new class(display_) Runnable { 151 Display display; 152 Control[1] lastFocus; 153 this( Display display){ this.display = display; } 154 public void run() { 155 if (( null !is cast(OleClientSite)lastFocus[0] ) && !lastFocus[0].isDisposed()) { 156 // ignore popup menus and dialogs 157 auto hwnd = OS.GetFocus(); 158 while (hwnd !is null) { 159 auto ownerHwnd = OS.GetWindow(hwnd, OS.GW_OWNER); 160 if (ownerHwnd !is null) { 161 display.timerExec(time, this); 162 return; 163 } 164 hwnd = OS.GetParent(hwnd); 165 } 166 } 167 if (lastFocus[0] is null || lastFocus[0].isDisposed() || !lastFocus[0].isFocusControl()) { 168 Control currentFocus = display.getFocusControl(); 169 if ( auto frame = cast(OleFrame)currentFocus ) { 170 currentFocus = frame.getCurrentDocument(); 171 } 172 if (lastFocus[0] !is currentFocus) { 173 Event event = new Event(); 174 if (( null !is cast(OleClientSite)lastFocus[0] ) && !lastFocus[0].isDisposed()) { 175 lastFocus[0].notifyListeners (SWT.FocusOut, event); 176 } 177 if (( null !is cast(OleClientSite)currentFocus ) && !currentFocus.isDisposed()) { 178 currentFocus.notifyListeners(SWT.FocusIn, event); 179 } 180 } 181 lastFocus[0] = currentFocus; 182 } 183 display.timerExec(time, this); 184 } 185 }; 186 display_.timerExec(time, timer); 187 } 188 private static void initMsgHook(Display display) { 189 if (display.getData(HHOOK) !is null) return; 190 //final Callback callback = new Callback(OleFrame.class, "getMsgProc", 3); //$NON-NLS-1$ 191 //int address = callback.getAddress(); 192 //if (address is 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); 193 int threadId = OS.GetCurrentThreadId(); 194 auto hHook_ = OS.SetWindowsHookEx(OS.WH_GETMESSAGE, &getMsgProc, null, threadId); 195 if (hHook_ is null) { 196 //callback.dispose(); 197 return; 198 } 199 display.setData(HHOOK, new ValueWrapperT!(void*)(hHook_)); 200 display.setData(HHOOKMSG, new ValueWrapperT!(MSG*)(new MSG())); 201 display.disposeExec(new class(hHook_) Runnable { 202 void* hHook; 203 this( void* hHook ){ this.hHook = hHook; } 204 public void run() { 205 if (hHook !is null) OS.UnhookWindowsHookEx(hHook); 206 //if (callback !is null) callback.dispose(); 207 } 208 }); 209 } 210 static extern(Windows) .LRESULT getMsgProc(int code, WPARAM wParam, LPARAM lParam) { 211 Display display = Display.getCurrent(); 212 if (display is null) return 0; 213 auto hHook = cast(ValueWrapperT!(void*))display.getData(HHOOK); 214 if (hHook is null) return 0; 215 if (code < 0) { 216 return OS.CallNextHookEx(hHook.value, code, wParam, lParam); 217 } 218 MSG* msg = cast(MSG*)(cast(ValueWrapperT!(MSG*))display.getData(HHOOKMSG)).value; 219 OS.MoveMemory(msg, lParam, MSG.sizeof); 220 int message = msg.message; 221 if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) { 222 if (display !is null) { 223 Widget widget = null; 224 auto hwnd = msg.hwnd; 225 while (hwnd !is null) { 226 widget = display.findWidget (hwnd); 227 if (widget !is null) break; 228 hwnd = OS.GetParent (hwnd); 229 } 230 if (widget !is null && (null !is cast(OleClientSite)widget )) { 231 OleClientSite site = cast(OleClientSite)widget; 232 if (site.handle is hwnd) { 233 bool consumed = false; 234 /* Allow activeX control to translate accelerators except when a menu is active. */ 235 int thread = OS.GetWindowThreadProcessId(msg.hwnd, null); 236 GUITHREADINFO* lpgui = new GUITHREADINFO(); 237 lpgui.cbSize = GUITHREADINFO.sizeof; 238 bool rc = cast(bool) OS.GetGUIThreadInfo(thread, lpgui); 239 int mask = OS.GUI_INMENUMODE | OS.GUI_INMOVESIZE | OS.GUI_POPUPMENUMODE | OS.GUI_SYSTEMMENUMODE; 240 if (!rc || (lpgui.flags & mask) is 0) { 241 OleFrame frame = site.frame; 242 frame.setData(CONSUME_KEY, null); 243 consumed = frame.translateOleAccelerator(msg); 244 if (frame.getData(CONSUME_KEY) !is null) consumed = false; 245 frame.setData(CONSUME_KEY, null); 246 } 247 bool accentKey = false; 248 switch (msg.message) { 249 case OS.WM_KEYDOWN: 250 case OS.WM_SYSKEYDOWN: { 251 static if (!OS.IsWinCE) { 252 switch (msg.wParam) { 253 case OS.VK_SHIFT: 254 case OS.VK_MENU: 255 case OS.VK_CONTROL: 256 case OS.VK_CAPITAL: 257 case OS.VK_NUMLOCK: 258 case OS.VK_SCROLL: 259 break; 260 default: { 261 /* 262 * Bug in Windows. The high bit in the result of MapVirtualKey() on 263 * Windows NT is bit 32 while the high bit on Windows 95 is bit 16. 264 * They should both be bit 32. The fix is to test the right bit. 265 */ 266 int mapKey = OS.MapVirtualKey (cast(int)/*64bit*/msg.wParam, 2); 267 if (mapKey !is 0) { 268 accentKey = (mapKey & (OS.IsWinNT ? 0x80000000 : 0x8000)) !is 0; 269 if (!accentKey) { 270 for (int i=0; i<ACCENTS.length; i++) { 271 int value = OS.VkKeyScan (ACCENTS [i]); 272 if (value !is -1 && (value & 0xFF) is msg.wParam) { 273 int state = value >> 8; 274 if ((OS.GetKeyState (OS.VK_SHIFT) < 0) is ((state & 0x1) !is 0) && 275 (OS.GetKeyState (OS.VK_CONTROL) < 0) is ((state & 0x2) !is 0) && 276 (OS.GetKeyState (OS.VK_MENU) < 0) is ((state & 0x4) !is 0)) { 277 if ((state & 0x7) !is 0) accentKey = true; 278 break; 279 } 280 } 281 } 282 } 283 } 284 break; 285 } 286 } 287 } 288 break; 289 } 290 default: 291 } 292 /* Allow OleClientSite to process key events before activeX control */ 293 if (!consumed && !accentKey && !ignoreNextKey) { 294 auto hwndOld = msg.hwnd; 295 msg.hwnd = site.handle; 296 consumed = OS.DispatchMessage (msg) is 1; 297 msg.hwnd = hwndOld; 298 } 299 switch (msg.message) { 300 case OS.WM_KEYDOWN: 301 case OS.WM_SYSKEYDOWN: { 302 switch (msg.wParam) { 303 case OS.VK_SHIFT: 304 case OS.VK_MENU: 305 case OS.VK_CONTROL: 306 case OS.VK_CAPITAL: 307 case OS.VK_NUMLOCK: 308 case OS.VK_SCROLL: 309 break; 310 default: { 311 ignoreNextKey = accentKey; 312 break; 313 } 314 } 315 break; 316 } 317 default: 318 break; 319 } 320 321 if (consumed) { 322 // In order to prevent this message from also being processed 323 // by the application, zero out message, wParam and lParam 324 msg.message = OS.WM_NULL; 325 msg.wParam = msg.lParam = 0; 326 OS.MoveMemory(lParam, msg, MSG.sizeof); 327 return 0; 328 } 329 } 330 } 331 } 332 } 333 return OS.CallNextHookEx( hHook.value, code, wParam, lParam); 334 } 335 /** 336 * Increment the count of references to this instance 337 * 338 * @return the current reference count 339 */ 340 int AddRef() { 341 refCount++; 342 return refCount; 343 } 344 private int ContextSensitiveHelp(int fEnterMode) { 345 return COM.S_OK; 346 } 347 private void createCOMInterfaces() { 348 iOleInPlaceFrame = new _IOleInPlaceFrameImpl(this); 349 } 350 private void disposeCOMInterfaces () { 351 iOleInPlaceFrame = null; 352 } 353 private HRESULT GetBorder(LPRECT lprectBorder) { 354 /* 355 The IOleInPlaceUIWindow::GetBorder function, when called on a document or frame window 356 object, returns the outer rectangle (relative to the window) where the object can put 357 toolbars or similar controls. 358 */ 359 if (lprectBorder is null) return COM.E_INVALIDARG; 360 RECT* rectBorder = new RECT(); 361 // Coordinates must be relative to the window 362 OS.GetClientRect(handle, lprectBorder); 363 return COM.S_OK; 364 } 365 /** 366 * 367 * Returns the application menu items that will appear in the Container location when an OLE Document 368 * is in-place activated. 369 * 370 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application 371 * is given the opportunity to merge some of its menus into the menubar. The application 372 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window 373 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help 374 * menu locations. Note that an application can insert more than one menu into a single location. 375 * 376 * @return the application menu items that will appear in the Container location when an OLE Document 377 * is in-place activated. 378 * 379 */ 380 public MenuItem[] getContainerMenus(){ 381 return containerMenuItems; 382 } 383 /** 384 * 385 * Returns the application menu items that will appear in the File location when an OLE Document 386 * is in-place activated. 387 * 388 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application 389 * is given the opportunity to merge some of its menus into the menubar. The application 390 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window 391 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help 392 * menu locations. Note that an application can insert more than one menu into a single location. 393 * 394 * @return the application menu items that will appear in the File location when an OLE Document 395 * is in-place activated. 396 * 397 */ 398 public MenuItem[] getFileMenus(){ 399 return fileMenuItems; 400 } 401 IOleInPlaceFrame getIOleInPlaceFrame() { 402 return iOleInPlaceFrame; 403 } 404 private ptrdiff_t getMenuItemID(HMENU hMenu, int index) { 405 ptrdiff_t id = 0; 406 MENUITEMINFO lpmii; 407 lpmii.cbSize = OS.MENUITEMINFO_sizeof; 408 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID; 409 OS.GetMenuItemInfo(hMenu, index, true, &lpmii); 410 if ((lpmii.fState & OS.MF_POPUP) is OS.MF_POPUP) { 411 id = cast(ptrdiff_t)lpmii.hSubMenu; 412 } else { 413 id = lpmii.wID; 414 } 415 return id; 416 } 417 private int GetWindow(HWND* phwnd) { 418 if (phwnd !is null) { 419 *phwnd = handle; 420 } 421 return COM.S_OK; 422 } 423 /** 424 * 425 * Returns the application menu items that will appear in the Window location when an OLE Document 426 * is in-place activated. 427 * 428 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application 429 * is given the opportunity to merge some of its menus into the menubar. The application 430 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window 431 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help 432 * menu locations. Note that an application can insert more than one menu into a single location. 433 * 434 * @return the application menu items that will appear in the Window location when an OLE Document 435 * is in-place activated. 436 * 437 */ 438 public MenuItem[] getWindowMenus(){ 439 return windowMenuItems; 440 } 441 private HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ) { 442 // locate menu bar 443 Menu menubar = getShell().getMenuBar(); 444 if (menubar is null || menubar.isDisposed()) { 445 int temp = 0; 446 COM.MoveMemory(lpMenuWidths, &temp, 4); 447 return COM.S_OK; 448 } 449 HMENU hMenu = menubar.handle; 450 451 // Create a holder for menu information. This will be passed down to 452 // the OS and the OS will fill in the requested information for each menu. 453 MENUITEMINFO lpmii; 454 auto hHeap = OS.GetProcessHeap(); 455 int cch = 128; 456 auto byteCount = cch * TCHAR.sizeof; 457 auto pszText = cast(TCHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); 458 lpmii.cbSize = OS.MENUITEMINFO_sizeof; 459 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA; 460 lpmii.dwTypeData = pszText; 461 lpmii.cch = cch; 462 463 // Loop over all "File-like" menus in the menubar and get information about the 464 // item from the OS. 465 int fileMenuCount = 0; 466 int newindex = 0; 467 if (this.fileMenuItems !is null) { 468 for (int i = 0; i < this.fileMenuItems.length; i++) { 469 MenuItem item = this.fileMenuItems[i]; 470 if (item !is null) { 471 int index = item.getParent().indexOf(item); 472 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the 473 // exact number of characters in name. Reset it to our max size 474 // before each call. 475 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { 476 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { 477 // keep track of the number of items 478 fileMenuCount++; 479 newindex++; 480 } 481 } 482 } 483 } 484 } 485 486 // copy the menu item count information to the pointer 487 COM.MoveMemory(lpMenuWidths, &fileMenuCount, 4); 488 489 // Loop over all "Container-like" menus in the menubar and get information about the 490 // item from the OS. 491 int containerMenuCount = 0; 492 if (this.containerMenuItems !is null) { 493 for (int i = 0; i < this.containerMenuItems.length; i++) { 494 MenuItem item = this.containerMenuItems[i]; 495 if (item !is null) { 496 int index = item.getParent().indexOf(item); 497 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the 498 // exact number of characters in name. Reset it to a large number 499 // before each call. 500 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { 501 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { 502 // keep track of the number of items 503 containerMenuCount++; 504 newindex++; 505 } 506 } 507 } 508 } 509 } 510 511 // copy the menu item count information to the pointer 512 COM.MoveMemory((cast(void*)lpMenuWidths) + 8, &containerMenuCount, 4); 513 514 // Loop over all "Window-like" menus in the menubar and get information about the 515 // item from the OS. 516 int windowMenuCount = 0; 517 if (this.windowMenuItems !is null) { 518 for (int i = 0; i < this.windowMenuItems.length; i++) { 519 MenuItem item = this.windowMenuItems[i]; 520 if (item !is null) { 521 int index = item.getParent().indexOf(item); 522 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the 523 // exact number of characters in name. Reset it to a large number 524 // before each call. 525 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { 526 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { 527 // keep track of the number of items 528 windowMenuCount++; 529 newindex++; 530 } 531 } 532 } 533 } 534 } 535 536 // copy the menu item count information to the pointer 537 COM.MoveMemory((cast(void*)lpMenuWidths) + 16, &windowMenuCount, 4); 538 539 // free resources used in querying the OS 540 if (pszText !is null) 541 OS.HeapFree(hHeap, 0, pszText); 542 return COM.S_OK; 543 } 544 void onActivate(Event e) { 545 if (objIOleInPlaceActiveObject !is null) { 546 objIOleInPlaceActiveObject.OnFrameWindowActivate(true); 547 } 548 if (objIOleInPlaceActiveObject !is null) { 549 objIOleInPlaceActiveObject.OnDocWindowActivate(true); 550 } 551 } 552 void onDeactivate(Event e) { 553 if (objIOleInPlaceActiveObject !is null) { 554 objIOleInPlaceActiveObject.OnFrameWindowActivate(false); 555 } 556 if (objIOleInPlaceActiveObject !is null) { 557 objIOleInPlaceActiveObject.OnDocWindowActivate(false); 558 } 559 } 560 private void onDispose(Event e) { 561 562 releaseObjectInterfaces(); 563 currentdoc = null; 564 565 this.Release(); 566 removeListener(SWT.Activate, listener); 567 removeListener(SWT.Deactivate, listener); 568 removeListener(SWT.Dispose, listener); 569 removeListener(SWT.Resize, listener); 570 removeListener(SWT.Move, listener); 571 } 572 private void onResize(Event e) { 573 if (objIOleInPlaceActiveObject !is null) { 574 RECT lpRect; 575 OS.GetClientRect(handle, &lpRect); 576 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true); 577 } 578 } 579 private HRESULT QueryInterface(REFCIID riid, void** ppvObject) { 580 // implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow 581 if (riid is null || ppvObject is null) 582 return COM.E_INVALIDARG; 583 584 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIOleInPlaceFrame) ) { 585 *ppvObject = cast(void*)cast(IOleInPlaceFrame)iOleInPlaceFrame; 586 AddRef(); 587 return COM.S_OK; 588 } 589 590 *ppvObject = null; 591 return COM.E_NOINTERFACE; 592 } 593 /** 594 * Decrement the count of references to this instance 595 * 596 * @return the current reference count 597 */ 598 int Release() { 599 refCount--; 600 if (refCount is 0){ 601 disposeCOMInterfaces(); 602 COM.CoFreeUnusedLibraries(); 603 } 604 return refCount; 605 } 606 private void releaseObjectInterfaces() { 607 if (objIOleInPlaceActiveObject !is null) { 608 objIOleInPlaceActiveObject.Release(); 609 } 610 objIOleInPlaceActiveObject = null; 611 } 612 private int RemoveMenus(HMENU hmenuShared) { 613 614 Menu menubar = getShell().getMenuBar(); 615 if (menubar is null || menubar.isDisposed()) return COM.S_FALSE; 616 617 auto hMenu = menubar.handle; 618 619 Vector ids = new Vector(); 620 if (this.fileMenuItems !is null) { 621 for (int i = 0; i < this.fileMenuItems.length; i++) { 622 MenuItem item = this.fileMenuItems[i]; 623 if (item !is null && !item.isDisposed()) { 624 int index = item.getParent().indexOf(item); 625 // get Id from original menubar 626 auto id = getMenuItemID(hMenu, index); 627 ids.addElement(new org.eclipse.swt.internal.LONG.LONG_PTR(id)); 628 } 629 } 630 } 631 if (this.containerMenuItems !is null) { 632 for (int i = 0; i < this.containerMenuItems.length; i++) { 633 MenuItem item = this.containerMenuItems[i]; 634 if (item !is null && !item.isDisposed()) { 635 int index = item.getParent().indexOf(item); 636 auto id = getMenuItemID(hMenu, index); 637 ids.addElement(new org.eclipse.swt.internal.LONG.LONG_PTR(id)); 638 } 639 } 640 } 641 if (this.windowMenuItems !is null) { 642 for (int i = 0; i < this.windowMenuItems.length; i++) { 643 MenuItem item = this.windowMenuItems[i]; 644 if (item !is null && !item.isDisposed()) { 645 int index = item.getParent().indexOf(item); 646 auto id = getMenuItemID(hMenu, index); 647 ids.addElement(new org.eclipse.swt.internal.LONG.LONG_PTR(id)); 648 } 649 } 650 } 651 int index = OS.GetMenuItemCount(hmenuShared) - 1; 652 for (int i = index; i >= 0; i--) { 653 auto id = getMenuItemID(hmenuShared, i); 654 if (ids.contains(new org.eclipse.swt.internal.LONG.LONG_PTR(id))){ 655 OS.RemoveMenu(hmenuShared, i, OS.MF_BYPOSITION); 656 } 657 } 658 return COM.S_OK; 659 } 660 private int RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) { 661 return COM.S_OK; 662 } 663 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) { 664 if (objIOleInPlaceActiveObject !is null) { 665 objIOleInPlaceActiveObject.Release(); 666 objIOleInPlaceActiveObject = null; 667 } 668 if (pActiveObject !is null) { 669 objIOleInPlaceActiveObject = pActiveObject; 670 objIOleInPlaceActiveObject.AddRef(); 671 } 672 673 return COM.S_OK; 674 } 675 676 private HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { 677 // A Control/Document can : 678 // Use its own toolbars, requesting border space of a specific size, or, 679 // Use no toolbars, but force the container to remove its toolbars by passing a 680 // valid BORDERWIDTHS structure containing nothing but zeros in the pborderwidths parameter, or, 681 // Use no toolbars but allow the in-place container to leave its toolbars up by 682 // passing NULL as the pborderwidths parameter. 683 if (objIOleInPlaceActiveObject is null) return COM.S_OK; 684 RECT* borderwidth = new RECT(); 685 if (pborderwidths is null || currentdoc is null ) return COM.S_OK; 686 687 COM.MoveMemory(borderwidth, pborderwidths, RECT.sizeof); 688 currentdoc.setBorderSpace(borderwidth); 689 690 return COM.S_OK; 691 } 692 /** 693 * 694 * Specify the menu items that should appear in the Container location when an OLE Document 695 * is in-place activated. 696 * 697 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application 698 * is given the opportunity to merge some of its menus into the menubar. The application 699 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window 700 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help 701 * menu locations. Note that an application can insert more than one menu into a single location. 702 * 703 * <p>This method must be called before in place activation of the OLE Document. After the Document 704 * is activated, the menu bar will not be modified until a subsequent activation. 705 * 706 * @param containerMenus an array of top level MenuItems to be inserted into the Container location of 707 * the menubar 708 */ 709 public void setContainerMenus(MenuItem[] containerMenus){ 710 containerMenuItems = containerMenus; 711 } 712 OleClientSite getCurrentDocument() { 713 return currentdoc; 714 } 715 void setCurrentDocument(OleClientSite doc) { 716 currentdoc = doc; 717 718 if (currentdoc !is null && objIOleInPlaceActiveObject !is null) { 719 RECT lpRect; 720 OS.GetClientRect(handle, &lpRect); 721 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true); 722 } 723 } 724 /** 725 * 726 * Specify the menu items that should appear in the File location when an OLE Document 727 * is in-place activated. 728 * 729 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application 730 * is given the opportunity to merge some of its menus into the menubar. The application 731 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window 732 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help 733 * menu locations. Note that an application can insert more than one menu into a single location. 734 * 735 * <p>This method must be called before in place activation of the OLE Document. After the Document 736 * is activated, the menu bar will not be modified until a subsequent activation. 737 * 738 * @param fileMenus an array of top level MenuItems to be inserted into the File location of 739 * the menubar 740 */ 741 public void setFileMenus(MenuItem[] fileMenus){ 742 fileMenuItems = fileMenus; 743 } 744 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ) { 745 IOleInPlaceActiveObject inPlaceActiveObject; 746 if (objIOleInPlaceActiveObject !is null) 747 inPlaceActiveObject = objIOleInPlaceActiveObject; 748 749 Menu menubar = getShell().getMenuBar(); 750 if (menubar is null || menubar.isDisposed()){ 751 return COM.OleSetMenuDescriptor(null, getShell().handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject); 752 } 753 754 HWND handle = menubar.getShell().handle; 755 756 if (hmenuShared is null && holemenu is null) { 757 // re-instate the original menu - this occurs on deactivation 758 hmenuShared = menubar.handle; 759 } 760 if (hmenuShared is null) return COM.E_FAIL; 761 762 OS.SetMenu(handle, hmenuShared); 763 OS.DrawMenuBar(handle); 764 765 return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject); 766 } 767 768 /** 769 * 770 * Set the menu items that should appear in the Window location when an OLE Document 771 * is in-place activated. 772 * 773 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application 774 * is given the opportunity to merge some of its menus into the menubar. The application 775 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window 776 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help 777 * menu locations. Note that an application can insert more than one menu into a single location. 778 * 779 * <p>This method must be called before in place activation of the OLE Document. After the Document 780 * is activated, the menu bar will not be modified until a subsequent activation. 781 * 782 * @param windowMenus an array of top level MenuItems to be inserted into the Window location of 783 * the menubar 784 */ 785 public void setWindowMenus(MenuItem[] windowMenus){ 786 windowMenuItems = windowMenus; 787 } 788 private bool translateOleAccelerator(MSG* msg) { 789 if (objIOleInPlaceActiveObject is null) return false; 790 int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg); 791 return (result != COM.S_FALSE && result != COM.E_NOTIMPL); 792 } 793 794 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ){ 795 Menu menubar = getShell().getMenuBar(); 796 if (menubar is null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE; 797 if (wID < 0) return COM.S_FALSE; 798 799 Shell shell = menubar.getShell(); 800 HWND hwnd = shell.handle; 801 HACCEL hAccel = cast(HACCEL)OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0); 802 if (hAccel is null) return COM.S_FALSE; 803 804 MSG msg = *lpmsg; 805 int result = OS.TranslateAccelerator(hwnd, hAccel, &msg); 806 return result == 0 ? COM.S_FALSE : COM.S_OK; 807 } 808 } 809 810 // implements IOleInPlaceFrame, IOleInPlaceUIWindow, IOleWindow, IUnknown 811 class _IOleInPlaceFrameImpl : IOleInPlaceFrame { 812 813 OleFrame parent; 814 this(OleFrame p) { parent = p; } 815 extern (Windows) : 816 // interface of IUnknown 817 HRESULT QueryInterface(REFCIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); } 818 ULONG AddRef() { return parent.AddRef(); } 819 ULONG Release() { return parent.Release(); } 820 821 // interface IOleWindow 822 HRESULT GetWindow( HWND * phwnd ) { return parent.GetWindow(phwnd); } 823 HRESULT ContextSensitiveHelp( BOOL fEnterMode ){ return COM.S_OK; } 824 825 //interface IOleInPlaceUIWindow 826 HRESULT GetBorder( LPRECT lprectBorder ) { return parent.GetBorder(lprectBorder); } 827 HRESULT RequestBorderSpace( LPCBORDERWIDTHS pborderwidths ){ return COM.S_OK; } 828 HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { return parent.SetBorderSpace(pborderwidths); } 829 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) { 830 return parent.SetActiveObject(pActiveObject, pszObjName); 831 } 832 833 // interface IOleInPlaceFrame : IOleInPlaceUIWindow 834 HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ){ 835 return parent.InsertMenus(hmenuShared, lpMenuWidths); 836 } 837 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ){ 838 return parent.SetMenu(hmenuShared, holemenu, hwndActiveObject); 839 } 840 HRESULT RemoveMenus( HMENU hmenuShared ) { 841 return parent.RemoveMenus(hmenuShared); 842 } 843 HRESULT SetStatusText( LPCOLESTR pszStatusText ) { return COM.E_NOTIMPL; } 844 HRESULT EnableModeless( BOOL fEnable ) { return COM.E_NOTIMPL; } 845 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ) { 846 return parent.TranslateAccelerator(lpmsg, wID); 847 } 848 849 } 850