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