| /******************************************************************************* |
| * Copyright (c) 2000, 2016 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.ole.win32; |
| |
| import java.util.*; |
| import java.util.List; |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.internal.*; |
| import org.eclipse.swt.internal.ole.win32.*; |
| import org.eclipse.swt.internal.win32.*; |
| import org.eclipse.swt.widgets.*; |
| |
| /** |
| * |
| * OleFrame is an OLE Container's top level frame. |
| * |
| * <p>This object implements the OLE Interfaces IUnknown and IOleInPlaceFrame |
| * |
| * <p>OleFrame allows the container to do the following: <ul> |
| * <li>position and size the ActiveX Control or OLE Document within the application |
| * <li>insert menu items from the application into the OLE Document's menu |
| * <li>activate and deactivate the OLE Document's menus |
| * <li>position the OLE Document's menu in the application |
| * <li>translate accelerator keystrokes intended for the container's frame</ul> |
| * |
| * <dl> |
| * <dt><b>Styles</b> <dd>BORDER |
| * <dt><b>Events</b> <dd>Dispose, Move, Resize |
| * </dl> |
| * |
| * @see <a href="http://www.eclipse.org/swt/snippets/#ole">OLE and ActiveX snippets</a> |
| * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: OLEExample, OleWebBrowser</a> |
| */ |
| final public class OleFrame extends Composite |
| { |
| // Interfaces for this Ole Client Container |
| private COMObject iUnknown; |
| private COMObject iOleInPlaceFrame; |
| |
| // Access to the embedded/linked Ole Object |
| private IOleInPlaceActiveObject objIOleInPlaceActiveObject; |
| |
| private OleClientSite currentdoc; |
| |
| private int refCount = 0; |
| |
| private MenuItem[] fileMenuItems; |
| private MenuItem[] containerMenuItems; |
| private MenuItem[] windowMenuItems; |
| |
| private Listener listener; |
| |
| private long /*int*/ shellHandle; |
| private long /*int*/ oldMenuHandle; |
| private long /*int*/ newMenuHandle; |
| private static long /*int*/ lastActivatedMenuHandle; |
| |
| private static String CHECK_FOCUS = "OLE_CHECK_FOCUS"; //$NON-NLS-1$ |
| private static String HHOOK = "OLE_HHOOK"; //$NON-NLS-1$ |
| private static String HHOOKMSG = "OLE_HHOOK_MSG"; //$NON-NLS-1$ |
| |
| private static boolean ignoreNextKey; |
| private static final short [] ACCENTS = new short [] {'~', '`', '\'', '^', '"'}; |
| |
| private static final String CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$ |
| private static final String ACCEL_KEY_HIT = "org.eclipse.swt.internal.win32.accelKeyHit"; //$NON-NLS-1$ |
| |
| /** |
| * Create an OleFrame child widget using style bits |
| * to select a particular look or set of properties. |
| * |
| * @param parent a composite widget (cannot be null) |
| * @param style the bitwise OR'ing of widget styles |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT when the parent is null |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread |
| * </ul> |
| * |
| */ |
| public OleFrame(Composite parent, int style) { |
| super(parent, style); |
| |
| createCOMInterfaces(); |
| |
| // setup cleanup proc |
| listener = e -> { |
| switch (e.type) { |
| case SWT.Activate : onActivate(e); break; |
| case SWT.Deactivate : onDeactivate(e); break; |
| case SWT.Dispose : onDispose(e); break; |
| case SWT.Resize : |
| case SWT.Move : onResize(e); break; |
| default : |
| OLE.error(SWT.ERROR_NOT_IMPLEMENTED); |
| } |
| }; |
| |
| |
| addListener(SWT.Activate, listener); |
| addListener(SWT.Deactivate, listener); |
| addListener(SWT.Dispose, listener); |
| |
| // inform inplaceactiveobject whenever frame resizes |
| addListener(SWT.Resize, listener); |
| |
| // inform inplaceactiveobject whenever frame moves |
| addListener(SWT.Move, listener); |
| |
| // Maintain a reference to yourself so that when |
| // ClientSites close, they don't take the frame away |
| // with them. |
| this.AddRef(); |
| |
| // Check for focus change |
| Display display = getDisplay(); |
| initCheckFocus(display); |
| initMsgHook(display); |
| } |
| private static void initCheckFocus (final Display display) { |
| if (display.getData(CHECK_FOCUS) != null) return; |
| display.setData(CHECK_FOCUS, CHECK_FOCUS); |
| final int time = 50; |
| final Runnable[] timer = new Runnable[1]; |
| final Control[] lastFocus = new Control[1]; |
| timer[0] = () -> { |
| if (lastFocus[0] instanceof OleClientSite && !lastFocus[0].isDisposed()) { |
| // ignore popup menus and dialogs |
| long /*int*/ hwnd = OS.GetFocus(); |
| while (hwnd != 0) { |
| long /*int*/ ownerHwnd = OS.GetWindow(hwnd, OS.GW_OWNER); |
| if (ownerHwnd != 0) { |
| display.timerExec(time, timer[0]); |
| return; |
| } |
| hwnd = OS.GetParent(hwnd); |
| } |
| } |
| if (lastFocus[0] == null || lastFocus[0].isDisposed() || !lastFocus[0].isFocusControl()) { |
| Control currentFocus = display.getFocusControl(); |
| if (currentFocus instanceof OleFrame) { |
| OleFrame frame = (OleFrame) currentFocus; |
| currentFocus = frame.getCurrentDocument(); |
| } |
| if (lastFocus[0] != currentFocus) { |
| Event event = new Event(); |
| if (lastFocus[0] instanceof OleClientSite && !lastFocus[0].isDisposed()) { |
| lastFocus[0].notifyListeners (SWT.FocusOut, event); |
| } |
| if (currentFocus instanceof OleClientSite && !currentFocus.isDisposed()) { |
| currentFocus.notifyListeners(SWT.FocusIn, event); |
| } |
| } |
| lastFocus[0] = currentFocus; |
| } |
| display.timerExec(time, timer[0]); |
| }; |
| display.timerExec(time, timer[0]); |
| } |
| private static void initMsgHook(Display display) { |
| if (display.getData(HHOOK) != null) return; |
| final Callback callback = new Callback(OleFrame.class, "getMsgProc", 3); //$NON-NLS-1$ |
| long /*int*/ address = callback.getAddress(); |
| if (address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); |
| int threadId = OS.GetCurrentThreadId(); |
| final long /*int*/ hHook = OS.SetWindowsHookEx(OS.WH_GETMESSAGE, address, 0, threadId); |
| if (hHook == 0) { |
| callback.dispose(); |
| return; |
| } |
| display.setData(HHOOK, new LONG(hHook)); |
| display.setData(HHOOKMSG, new MSG()); |
| display.disposeExec(() -> { |
| if (hHook != 0) OS.UnhookWindowsHookEx(hHook); |
| if (callback != null) callback.dispose(); |
| }); |
| } |
| static long /*int*/ getMsgProc(long /*int*/ code, long /*int*/ wParam, long /*int*/ lParam) { |
| Display display = Display.getCurrent(); |
| if (display == null) return 0; |
| LONG hHook = (LONG)display.getData(HHOOK); |
| if (hHook == null) return 0; |
| if (code < 0 || (wParam & OS.PM_REMOVE) == 0) { |
| return OS.CallNextHookEx(hHook.value, (int)/*64*/code, wParam, lParam); |
| } |
| MSG msg = (MSG)display.getData(HHOOKMSG); |
| OS.MoveMemory(msg, lParam, MSG.sizeof); |
| int message = msg.message; |
| if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) { |
| if (display != null) { |
| Widget widget = null; |
| long /*int*/ hwnd = msg.hwnd; |
| while (hwnd != 0) { |
| widget = display.findWidget (hwnd); |
| if (widget != null) break; |
| hwnd = OS.GetParent (hwnd); |
| } |
| if (widget != null && widget instanceof OleClientSite) { |
| OleClientSite site = (OleClientSite)widget; |
| if (site.handle == hwnd) { |
| boolean consumed = false; |
| /* Allow activeX control to translate accelerators except when a menu is active. */ |
| int thread = OS.GetWindowThreadProcessId(msg.hwnd, null); |
| GUITHREADINFO lpgui = new GUITHREADINFO(); |
| lpgui.cbSize = GUITHREADINFO.sizeof; |
| boolean rc = OS.GetGUIThreadInfo(thread, lpgui); |
| int mask = OS.GUI_INMENUMODE | OS.GUI_INMOVESIZE | OS.GUI_POPUPMENUMODE | OS.GUI_SYSTEMMENUMODE; |
| if (!rc || (lpgui.flags & mask) == 0) { |
| OleFrame frame = site.frame; |
| frame.setData(CONSUME_KEY, null); |
| display.setData(ACCEL_KEY_HIT, Boolean.TRUE); |
| consumed = frame.translateOleAccelerator(msg); |
| /* translateOleAccelerator() may send client events, ensure that the frame and display are still valid */ |
| if (display.isDisposed()) return 0; |
| display.setData(ACCEL_KEY_HIT, Boolean.FALSE); |
| if (frame.isDisposed()) return 0; |
| String value = (String)frame.getData(CONSUME_KEY); |
| if (value != null) consumed = value.equals("true"); //$NON-NLS-1$ |
| frame.setData(CONSUME_KEY, null); |
| } |
| boolean accentKey = false; |
| switch (msg.message) { |
| case OS.WM_KEYDOWN: |
| case OS.WM_SYSKEYDOWN: { |
| if (!OS.IsWinCE) { |
| switch ((int)/*64*/msg.wParam) { |
| case OS.VK_SHIFT: |
| case OS.VK_MENU: |
| case OS.VK_CONTROL: |
| case OS.VK_CAPITAL: |
| case OS.VK_NUMLOCK: |
| case OS.VK_SCROLL: |
| break; |
| default: { |
| /* |
| * Bug in Windows. The high bit in the result of MapVirtualKey() on |
| * Windows NT is bit 32 while the high bit on Windows 95 is bit 16. |
| * They should both be bit 32. The fix is to test the right bit. |
| */ |
| int mapKey = OS.MapVirtualKey ((int)/*64*/msg.wParam, 2); |
| if (mapKey != 0) { |
| accentKey = (mapKey & (OS.IsWinNT ? 0x80000000 : 0x8000)) != 0; |
| if (!accentKey) { |
| for (int i=0; i<ACCENTS.length; i++) { |
| int value = OS.VkKeyScan (ACCENTS [i]); |
| if (value != -1 && (value & 0xFF) == msg.wParam) { |
| int state = value >> 8; |
| if ((OS.GetKeyState (OS.VK_SHIFT) < 0) == ((state & 0x1) != 0) && |
| (OS.GetKeyState (OS.VK_CONTROL) < 0) == ((state & 0x2) != 0) && |
| (OS.GetKeyState (OS.VK_MENU) < 0) == ((state & 0x4) != 0)) { |
| if ((state & 0x7) != 0) accentKey = true; |
| break; |
| } |
| } |
| } |
| } |
| } |
| break; |
| } |
| } |
| } |
| break; |
| } |
| } |
| /* Allow OleClientSite to process key events before activeX control */ |
| if (!consumed && !accentKey && !ignoreNextKey) { |
| long /*int*/ hwndOld = msg.hwnd; |
| msg.hwnd = site.handle; |
| consumed = OS.DispatchMessage (msg) == 1; |
| msg.hwnd = hwndOld; |
| } |
| switch (msg.message) { |
| case OS.WM_KEYDOWN: |
| case OS.WM_SYSKEYDOWN: { |
| switch ((int)/*64*/msg.wParam) { |
| case OS.VK_SHIFT: |
| case OS.VK_MENU: |
| case OS.VK_CONTROL: |
| case OS.VK_CAPITAL: |
| case OS.VK_NUMLOCK: |
| case OS.VK_SCROLL: |
| break; |
| default: { |
| ignoreNextKey = accentKey; |
| break; |
| } |
| } |
| } |
| } |
| |
| if (consumed) { |
| // In order to prevent this message from also being processed |
| // by the application, zero out message, wParam and lParam |
| msg.message = OS.WM_NULL; |
| msg.wParam = msg.lParam = 0; |
| OS.MoveMemory(lParam, msg, MSG.sizeof); |
| return 0; |
| } |
| } |
| } |
| } |
| } |
| return OS.CallNextHookEx(hHook.value, (int)/*64*/code, wParam, lParam); |
| } |
| /** |
| * Increment the count of references to this instance |
| * |
| * @return the current reference count |
| */ |
| int AddRef() { |
| refCount++; |
| return refCount; |
| } |
| private int ContextSensitiveHelp(int fEnterMode) { |
| return COM.S_OK; |
| } |
| private void createCOMInterfaces() { |
| // Create each of the interfaces that this object implements |
| iUnknown = new COMObject(new int[]{2, 0, 0}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| }; |
| |
| iOleInPlaceFrame = new COMObject(new int[]{2, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 1, 2}){ |
| @Override |
| public long /*int*/ method0(long /*int*/[] args) {return QueryInterface(args[0], args[1]);} |
| @Override |
| public long /*int*/ method1(long /*int*/[] args) {return AddRef();} |
| @Override |
| public long /*int*/ method2(long /*int*/[] args) {return Release();} |
| @Override |
| public long /*int*/ method3(long /*int*/[] args) {return GetWindow(args[0]);} |
| @Override |
| public long /*int*/ method4(long /*int*/[] args) {return ContextSensitiveHelp((int)/*64*/args[0]);} |
| @Override |
| public long /*int*/ method5(long /*int*/[] args) {return GetBorder(args[0]);} |
| @Override |
| public long /*int*/ method6(long /*int*/[] args) {return RequestBorderSpace(args[0]);} |
| @Override |
| public long /*int*/ method7(long /*int*/[] args) {return SetBorderSpace(args[0]);} |
| @Override |
| public long /*int*/ method8(long /*int*/[] args) {return SetActiveObject(args[0], args[1]);} |
| @Override |
| public long /*int*/ method9(long /*int*/[] args) {return InsertMenus(args[0], args[1]);} |
| @Override |
| public long /*int*/ method10(long /*int*/[] args) {return SetMenu(args[0], args[1], args[2]);} |
| @Override |
| public long /*int*/ method11(long /*int*/[] args) {return RemoveMenus(args[0]);} |
| // method12 SetStatusText - not implemented |
| // method13 EnableModeless - not implemented |
| @Override |
| public long /*int*/ method14(long /*int*/[] args) {return TranslateAccelerator(args[0], (int)/*64*/args[1]);} |
| }; |
| } |
| private void disposeCOMInterfaces () { |
| |
| if (iUnknown != null) |
| iUnknown.dispose(); |
| iUnknown = null; |
| |
| if (iOleInPlaceFrame != null) |
| iOleInPlaceFrame.dispose(); |
| iOleInPlaceFrame = null; |
| } |
| private int GetBorder(long /*int*/ lprectBorder) { |
| /* |
| The IOleInPlaceUIWindow::GetBorder function, when called on a document or frame window |
| object, returns the outer rectangle (relative to the window) where the object can put |
| toolbars or similar controls. |
| */ |
| if (lprectBorder == 0) return COM.E_INVALIDARG; |
| RECT rectBorder = new RECT(); |
| // Coordinates must be relative to the window |
| OS.GetClientRect(handle, rectBorder); |
| OS.MoveMemory(lprectBorder, rectBorder, RECT.sizeof); |
| return COM.S_OK; |
| } |
| /** |
| * |
| * Returns the application menu items that will appear in the Container location when an OLE Document |
| * is in-place activated. |
| * |
| * <p>When an OLE Document is in-place active, the Document provides its own menus but the application |
| * is given the opportunity to merge some of its menus into the menubar. The application |
| * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window |
| * (far right just before Help). The OLE Document retains control of the Edit, Object and Help |
| * menu locations. Note that an application can insert more than one menu into a single location. |
| * |
| * @return the application menu items that will appear in the Container location when an OLE Document |
| * is in-place activated. |
| * |
| */ |
| public MenuItem[] getContainerMenus(){ |
| return containerMenuItems; |
| } |
| /** |
| * |
| * Returns the application menu items that will appear in the File location when an OLE Document |
| * is in-place activated. |
| * |
| * <p>When an OLE Document is in-place active, the Document provides its own menus but the application |
| * is given the opportunity to merge some of its menus into the menubar. The application |
| * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window |
| * (far right just before Help). The OLE Document retains control of the Edit, Object and Help |
| * menu locations. Note that an application can insert more than one menu into a single location. |
| * |
| * @return the application menu items that will appear in the File location when an OLE Document |
| * is in-place activated. |
| * |
| */ |
| public MenuItem[] getFileMenus(){ |
| return fileMenuItems; |
| } |
| long /*int*/ getIOleInPlaceFrame() { |
| return iOleInPlaceFrame.getAddress(); |
| } |
| private long /*int*/ getMenuItemID(long /*int*/ hMenu, int index) { |
| long /*int*/ id = 0; |
| MENUITEMINFO lpmii = new MENUITEMINFO(); |
| lpmii.cbSize = MENUITEMINFO.sizeof; |
| lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID; |
| OS.GetMenuItemInfo(hMenu, index, true, lpmii); |
| if ((lpmii.fState & OS.MF_POPUP) == OS.MF_POPUP) { |
| id = lpmii.hSubMenu; |
| } else { |
| id = lpmii.wID; |
| } |
| return id; |
| } |
| private int GetWindow(long /*int*/ phwnd) { |
| if (phwnd != 0) { |
| COM.MoveMemory(phwnd, new long /*int*/[] {handle}, OS.PTR_SIZEOF); |
| } |
| return COM.S_OK; |
| } |
| /** |
| * |
| * Returns the application menu items that will appear in the Window location when an OLE Document |
| * is in-place activated. |
| * |
| * <p>When an OLE Document is in-place active, the Document provides its own menus but the application |
| * is given the opportunity to merge some of its menus into the menubar. The application |
| * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window |
| * (far right just before Help). The OLE Document retains control of the Edit, Object and Help |
| * menu locations. Note that an application can insert more than one menu into a single location. |
| * |
| * @return the application menu items that will appear in the Window location when an OLE Document |
| * is in-place activated. |
| * |
| */ |
| public MenuItem[] getWindowMenus(){ |
| return windowMenuItems; |
| } |
| private int InsertMenus(long /*int*/ hmenuShared, long /*int*/ lpMenuWidths) { |
| // locate menu bar |
| Menu menubar = getShell().getMenuBar(); |
| if (menubar == null || menubar.isDisposed()) { |
| COM.MoveMemory(lpMenuWidths, new int[] {0}, 4); |
| return COM.S_OK; |
| } |
| long /*int*/ hMenu = menubar.handle; |
| |
| // Create a holder for menu information. This will be passed down to |
| // the OS and the OS will fill in the requested information for each menu. |
| MENUITEMINFO lpmii = new MENUITEMINFO(); |
| long /*int*/ hHeap = OS.GetProcessHeap(); |
| int cch = 128; |
| int byteCount = cch * TCHAR.sizeof; |
| long /*int*/ pszText = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); |
| lpmii.cbSize = MENUITEMINFO.sizeof; |
| lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA; |
| lpmii.dwTypeData = pszText; |
| lpmii.cch = cch; |
| |
| // Loop over all "File-like" menus in the menubar and get information about the |
| // item from the OS. |
| int fileMenuCount = 0; |
| int newindex = 0; |
| if (this.fileMenuItems != null) { |
| for (int i = 0; i < this.fileMenuItems.length; i++) { |
| MenuItem item = this.fileMenuItems[i]; |
| if (item != null) { |
| int index = item.getParent().indexOf(item); |
| lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the |
| // exact number of characters in name. Reset it to our max size |
| // before each call. |
| if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) { |
| if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) { |
| // keep track of the number of items |
| fileMenuCount++; |
| newindex++; |
| } |
| } |
| } |
| } |
| } |
| |
| // copy the menu item count information to the pointer |
| COM.MoveMemory(lpMenuWidths, new int[] {fileMenuCount}, 4); |
| |
| // Loop over all "Container-like" menus in the menubar and get information about the |
| // item from the OS. |
| int containerMenuCount = 0; |
| if (this.containerMenuItems != null) { |
| for (int i = 0; i < this.containerMenuItems.length; i++) { |
| MenuItem item = this.containerMenuItems[i]; |
| if (item != null) { |
| int index = item.getParent().indexOf(item); |
| lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the |
| // exact number of characters in name. Reset it to a large number |
| // before each call. |
| if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) { |
| if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) { |
| // keep track of the number of items |
| containerMenuCount++; |
| newindex++; |
| } |
| } |
| } |
| } |
| } |
| |
| // copy the menu item count information to the pointer |
| COM.MoveMemory(lpMenuWidths + 8, new int[] {containerMenuCount}, 4); |
| |
| // Loop over all "Window-like" menus in the menubar and get information about the |
| // item from the OS. |
| int windowMenuCount = 0; |
| if (this.windowMenuItems != null) { |
| for (int i = 0; i < this.windowMenuItems.length; i++) { |
| MenuItem item = this.windowMenuItems[i]; |
| if (item != null) { |
| int index = item.getParent().indexOf(item); |
| lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the |
| // exact number of characters in name. Reset it to a large number |
| // before each call. |
| if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) { |
| if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) { |
| // keep track of the number of items |
| windowMenuCount++; |
| newindex++; |
| } |
| } |
| } |
| } |
| } |
| |
| // copy the menu item count information to the pointer |
| COM.MoveMemory(lpMenuWidths + 16, new int[] {windowMenuCount}, 4); |
| |
| // free resources used in querying the OS |
| if (pszText != 0) |
| OS.HeapFree(hHeap, 0, pszText); |
| return COM.S_OK; |
| } |
| void onActivate(Event e) { |
| if (objIOleInPlaceActiveObject != null) { |
| objIOleInPlaceActiveObject.OnFrameWindowActivate(true); |
| } |
| } |
| void onDeactivate(Event e) { |
| if (objIOleInPlaceActiveObject != null) { |
| objIOleInPlaceActiveObject.OnFrameWindowActivate(false); |
| } |
| } |
| private void onDispose(Event e) { |
| |
| releaseObjectInterfaces(); |
| currentdoc = null; |
| |
| this.Release(); |
| removeListener(SWT.Activate, listener); |
| removeListener(SWT.Deactivate, listener); |
| removeListener(SWT.Dispose, listener); |
| removeListener(SWT.Resize, listener); |
| removeListener(SWT.Move, listener); |
| } |
| void onFocusIn(Event e) { |
| if (lastActivatedMenuHandle != newMenuHandle) |
| currentdoc.doVerb(OLE.OLEIVERB_SHOW); |
| if (OS.GetMenu(shellHandle) != newMenuHandle) |
| OS.SetMenu(shellHandle, newMenuHandle); |
| } |
| void onFocusOut(Event e) { |
| Control control = getDisplay().getFocusControl(); |
| if (OS.GetMenu(shellHandle) != oldMenuHandle && control != null && control.handle != shellHandle) |
| OS.SetMenu(shellHandle, oldMenuHandle); |
| } |
| private void onResize(Event e) { |
| if (objIOleInPlaceActiveObject != null) { |
| RECT lpRect = new RECT(); |
| OS.GetClientRect(handle, lpRect); |
| objIOleInPlaceActiveObject.ResizeBorder(lpRect, iOleInPlaceFrame.getAddress(), true); |
| } |
| } |
| private int QueryInterface(long /*int*/ riid, long /*int*/ ppvObject) { |
| // implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow |
| if (riid == 0 || ppvObject == 0) |
| return COM.E_INVALIDARG; |
| GUID guid = new GUID(); |
| COM.MoveMemory(guid, riid, GUID.sizeof); |
| if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIOleInPlaceFrame) ) { |
| COM.MoveMemory(ppvObject, new long /*int*/ [] {iOleInPlaceFrame.getAddress()}, OS.PTR_SIZEOF); |
| AddRef(); |
| return COM.S_OK; |
| } |
| |
| COM.MoveMemory(ppvObject, new long /*int*/ [] {0}, OS.PTR_SIZEOF); |
| return COM.E_NOINTERFACE; |
| } |
| /** |
| * Decrement the count of references to this instance |
| * |
| * @return the current reference count |
| */ |
| int Release() { |
| refCount--; |
| if (refCount == 0){ |
| disposeCOMInterfaces(); |
| if (COM.FreeUnusedLibraries) { |
| COM.CoFreeUnusedLibraries(); |
| } |
| } |
| return refCount; |
| } |
| private void releaseObjectInterfaces() { |
| if (objIOleInPlaceActiveObject != null) { |
| objIOleInPlaceActiveObject.Release(); |
| } |
| objIOleInPlaceActiveObject = null; |
| } |
| private int RemoveMenus(long /*int*/ hmenuShared) { |
| |
| Menu menubar = getShell().getMenuBar(); |
| if (menubar == null || menubar.isDisposed()) return COM.S_FALSE; |
| |
| long /*int*/ hMenu = menubar.handle; |
| |
| List<LONG> ids = new ArrayList<>(); |
| if (this.fileMenuItems != null) { |
| for (int i = 0; i < this.fileMenuItems.length; i++) { |
| MenuItem item = this.fileMenuItems[i]; |
| if (item != null && !item.isDisposed()) { |
| int index = item.getParent().indexOf(item); |
| // get Id from original menubar |
| long /*int*/ id = getMenuItemID(hMenu, index); |
| ids.add(new LONG(id)); |
| } |
| } |
| } |
| if (this.containerMenuItems != null) { |
| for (int i = 0; i < this.containerMenuItems.length; i++) { |
| MenuItem item = this.containerMenuItems[i]; |
| if (item != null && !item.isDisposed()) { |
| int index = item.getParent().indexOf(item); |
| long /*int*/ id = getMenuItemID(hMenu, index); |
| ids.add(new LONG(id)); |
| } |
| } |
| } |
| if (this.windowMenuItems != null) { |
| for (int i = 0; i < this.windowMenuItems.length; i++) { |
| MenuItem item = this.windowMenuItems[i]; |
| if (item != null && !item.isDisposed()) { |
| int index = item.getParent().indexOf(item); |
| long /*int*/ id = getMenuItemID(hMenu, index); |
| ids.add(new LONG(id)); |
| } |
| } |
| } |
| int index = OS.GetMenuItemCount(hmenuShared) - 1; |
| for (int i = index; i >= 0; i--) { |
| long /*int*/ id = getMenuItemID(hmenuShared, i); |
| if (ids.contains(new LONG(id))){ |
| OS.RemoveMenu(hmenuShared, i, OS.MF_BYPOSITION); |
| } |
| } |
| return COM.S_OK; |
| } |
| private int RequestBorderSpace(long /*int*/ pborderwidths) { |
| return COM.S_OK; |
| } |
| int SetActiveObject(long /*int*/ pActiveObject, long /*int*/ pszObjName) { |
| if (objIOleInPlaceActiveObject != null) { |
| objIOleInPlaceActiveObject.Release(); |
| objIOleInPlaceActiveObject = null; |
| } |
| if (pActiveObject != 0) { |
| objIOleInPlaceActiveObject = new IOleInPlaceActiveObject(pActiveObject); |
| objIOleInPlaceActiveObject.AddRef(); |
| } |
| |
| return COM.S_OK; |
| } |
| private int SetBorderSpace(long /*int*/ pborderwidths) { |
| // A Control/Document can : |
| // Use its own toolbars, requesting border space of a specific size, or, |
| // Use no toolbars, but force the container to remove its toolbars by passing a |
| // valid BORDERWIDTHS structure containing nothing but zeros in the pborderwidths parameter, or, |
| // Use no toolbars but allow the in-place container to leave its toolbars up by |
| // passing NULL as the pborderwidths parameter. |
| if (objIOleInPlaceActiveObject == null) return COM.S_OK; |
| RECT borderwidth = new RECT(); |
| if (pborderwidths == 0 || currentdoc == null ) return COM.S_OK; |
| |
| COM.MoveMemory(borderwidth, pborderwidths, RECT.sizeof); |
| currentdoc.setBorderSpace(borderwidth); |
| |
| return COM.S_OK; |
| } |
| /** |
| * |
| * Specify the menu items that should appear in the Container location when an OLE Document |
| * is in-place activated. |
| * |
| * <p>When an OLE Document is in-place active, the Document provides its own menus but the application |
| * is given the opportunity to merge some of its menus into the menubar. The application |
| * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window |
| * (far right just before Help). The OLE Document retains control of the Edit, Object and Help |
| * menu locations. Note that an application can insert more than one menu into a single location. |
| * |
| * <p>This method must be called before in place activation of the OLE Document. After the Document |
| * is activated, the menu bar will not be modified until a subsequent activation. |
| * |
| * @param containerMenus an array of top level MenuItems to be inserted into the Container location of |
| * the menubar |
| */ |
| public void setContainerMenus(MenuItem[] containerMenus){ |
| containerMenuItems = containerMenus; |
| } |
| OleClientSite getCurrentDocument() { |
| return currentdoc; |
| } |
| void setCurrentDocument(OleClientSite doc) { |
| currentdoc = doc; |
| |
| if (currentdoc != null && objIOleInPlaceActiveObject != null) { |
| RECT lpRect = new RECT(); |
| OS.GetClientRect(handle, lpRect); |
| objIOleInPlaceActiveObject.ResizeBorder(lpRect, iOleInPlaceFrame.getAddress(), true); |
| } |
| } |
| /** |
| * |
| * Specify the menu items that should appear in the File location when an OLE Document |
| * is in-place activated. |
| * |
| * <p>When an OLE Document is in-place active, the Document provides its own menus but the application |
| * is given the opportunity to merge some of its menus into the menubar. The application |
| * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window |
| * (far right just before Help). The OLE Document retains control of the Edit, Object and Help |
| * menu locations. Note that an application can insert more than one menu into a single location. |
| * |
| * <p>This method must be called before in place activation of the OLE Document. After the Document |
| * is activated, the menu bar will not be modified until a subsequent activation. |
| * |
| * @param fileMenus an array of top level MenuItems to be inserted into the File location of |
| * the menubar |
| */ |
| public void setFileMenus(MenuItem[] fileMenus){ |
| fileMenuItems = fileMenus; |
| } |
| private int SetMenu(long /*int*/ hmenuShared, long /*int*/ holemenu, long /*int*/ hwndActiveObject) { |
| long /*int*/ inPlaceActiveObject = 0; |
| if (objIOleInPlaceActiveObject != null) |
| inPlaceActiveObject = objIOleInPlaceActiveObject.getAddress(); |
| |
| Menu menubar = getShell().getMenuBar(); |
| if (menubar == null || menubar.isDisposed()){ |
| return COM.OleSetMenuDescriptor(0, getShell().handle, hwndActiveObject, iOleInPlaceFrame.getAddress(), inPlaceActiveObject); |
| } |
| |
| long /*int*/ handle = menubar.getShell().handle; |
| |
| if (hmenuShared == 0 && holemenu == 0) { |
| // re-instate the original menu - this occurs on deactivation |
| hmenuShared = menubar.handle; |
| } |
| if (hmenuShared == 0) return COM.E_FAIL; |
| |
| shellHandle = handle; |
| oldMenuHandle = menubar.handle; |
| newMenuHandle = hmenuShared; |
| lastActivatedMenuHandle = newMenuHandle; |
| |
| return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame.getAddress(), inPlaceActiveObject); |
| } |
| /** |
| * |
| * Set the menu items that should appear in the Window location when an OLE Document |
| * is in-place activated. |
| * |
| * <p>When an OLE Document is in-place active, the Document provides its own menus but the application |
| * is given the opportunity to merge some of its menus into the menubar. The application |
| * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window |
| * (far right just before Help). The OLE Document retains control of the Edit, Object and Help |
| * menu locations. Note that an application can insert more than one menu into a single location. |
| * |
| * <p>This method must be called before in place activation of the OLE Document. After the Document |
| * is activated, the menu bar will not be modified until a subsequent activation. |
| * |
| * @param windowMenus an array of top level MenuItems to be inserted into the Window location of |
| * the menubar |
| */ |
| public void setWindowMenus(MenuItem[] windowMenus){ |
| windowMenuItems = windowMenus; |
| } |
| private boolean translateOleAccelerator(MSG msg) { |
| if (objIOleInPlaceActiveObject == null) return false; |
| int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg); |
| return (result != COM.S_FALSE && result != COM.E_NOTIMPL); |
| } |
| private int TranslateAccelerator(long /*int*/ lpmsg, int wID){ |
| Menu menubar = getShell().getMenuBar(); |
| if (menubar == null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE; |
| if (wID < 0) return COM.S_FALSE; |
| |
| Shell shell = menubar.getShell(); |
| long /*int*/ hwnd = shell.handle; |
| long /*int*/ hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0); |
| if (hAccel == 0) return COM.S_FALSE; |
| |
| MSG msg = new MSG(); |
| OS.MoveMemory(msg, lpmsg, MSG.sizeof); |
| int result = OS.TranslateAccelerator(hwnd, hAccel, msg); |
| return result == 0 ? COM.S_FALSE : COM.S_OK; |
| } |
| } |