1 //------------------------------------------------------------------------------
2 // <copyright file="WindowPane.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 using Microsoft
.VisualStudio
.OLE
.Interop
;
9 using Microsoft
.VisualStudio
.Shell
.Interop
;
10 using System
.ComponentModel
;
11 using System
.ComponentModel
.Design
;
12 using System
.Windows
.Forms
;
13 using System
.Security
.Permissions
;
15 using IDropTarget
= Microsoft
.VisualStudio
.OLE
.Interop
.IDropTarget
;
16 using IOleServiceProvider
= Microsoft
.VisualStudio
.OLE
.Interop
.IServiceProvider
;
17 using IServiceProvider
= System
.IServiceProvider
;
18 using IMessageFilter
= System
.Windows
.Forms
.IMessageFilter
;
20 namespace Microsoft
.VisualStudio
.Shell
{
22 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar"]/*' />
24 /// This class is the base class for forms that need to be displayed as modal dialogs inside VisualStudio.
27 public class DialogContainerWithToolbar
: Form
,
33 /// This class is used to change the control contained by the form to a
34 /// IVsWindowPane. This is expecially needed if the control is a form,
35 /// because WinForms will not allow us to make it child of another form.
37 private class WindowPaneAdapter
: WindowPane
39 private Control control
;
40 private DialogContainerWithToolbar container
;
41 private IntPtr paneHwnd
;
48 public WindowPaneAdapter(DialogContainerWithToolbar container
, Control control
) :
49 base ((IServiceProvider
)container
)
51 this.container
= container
;
52 this.paneHwnd
= IntPtr
.Zero
;
53 this.control
= control
;
56 protected override void Dispose(bool disposing
)
65 paneHwnd
= IntPtr
.Zero
;
67 base.Dispose(disposing
);
72 get { return paneHwnd; }
80 // Create the pane at the specific coordinates.
81 public void Create(int left
, int top
, int height
, int width
)
83 // Check if the pane was created before.
84 if (IntPtr
.Zero
!= paneHwnd
)
85 throw new InvalidOperationException();
88 NativeMethods
.ThrowOnFailure(
89 ((IVsWindowPane
)this).CreatePaneWindow(container
.Handle
, left
, top
, width
, height
, out paneHwnd
));
91 // Store the coordinates
98 // Returns the IWin32Window interface (used to access the handle of the control)
99 public override IWin32Window Window
101 get { return (IWin32Window)control; }
104 // Move the the pane to the specific coordinates.
105 public void Move(int left
, int top
, int height
, int width
)
107 if (IntPtr
.Zero
== Handle
)
110 bool result
= UnsafeNativeMethods
.SetWindowPos(
117 NativeMethods
.SWP_NOZORDER
| NativeMethods
.SWP_NOACTIVATE
);
120 throw new Exception();
124 this.height
= height
;
140 get { return height; }
145 get { return width; }
149 private class ShowDialogContainer
: Container
151 private IServiceProvider provider
;
152 public ShowDialogContainer(IServiceProvider sp
)
157 protected override object GetService(Type serviceType
)
159 if (provider
!= null)
161 object service
= provider
.GetService(serviceType
);
165 return base.GetService(serviceType
);
169 // Variables to handle the contained control
170 private WindowPaneAdapter containedForm
;
171 private System
.Drawing
.Size controlSize
;
174 private IVsToolWindowToolbarHost toolbarHost
;
175 private RECT toolbarRect
;
176 private CommandID toolbarCommandId
;
177 private VSTWT_LOCATION toolbarLocation
;
178 private IDropTarget toolbarDropTarget
;
181 private IServiceProvider provider
;
182 private OleMenuCommandService commandService
;
183 private uint commandTargetCookie
;
185 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.DialogContainerWithToolbar"]/*' />
187 /// Constructor of the DialogContainerWithToolbar. This constructor allow the caller to set a IServiceProvider,
188 /// the conatined control and an additional IOleCommandTarget implementation that will be chained to the one
189 /// implemented by OleMenuCommandTarget.
191 public DialogContainerWithToolbar(IServiceProvider sp
, Control contained
, IOleCommandTarget parentCommandTarget
)
193 if (null == contained
)
194 throw new ArgumentNullException("contained");
197 throw new ArgumentNullException("sp");
199 PrivateInit(sp
, contained
, parentCommandTarget
);
202 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.DialogContainerWithToolbar1"]/*' />
204 /// Constructor of the DialogContainerWithToolbar. This constructor allow the caller to set a IServiceProvider and
205 /// the conatined control.
207 public DialogContainerWithToolbar(IServiceProvider sp
, Control contained
)
209 if (null == contained
)
210 throw new ArgumentNullException("contained");
213 throw new ArgumentNullException("sp");
215 IOleCommandTarget parentTarget
= contained
as IOleCommandTarget
;
216 PrivateInit(sp
, contained
, parentTarget
);
219 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.DialogContainerWithToolbar2"]/*' />
221 /// Constructor of the DialogContainerWithToolbar. This constructor allow the caller to set a IServiceProvider.
223 public DialogContainerWithToolbar(IServiceProvider sp
)
226 throw new ArgumentNullException("sp");
228 PrivateInit(sp
, null, null);
231 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.DialogContainerWithToolbar3"]/*' />
233 /// Constructor of the DialogContainerWithToolbar.
235 public DialogContainerWithToolbar()
237 PrivateInit(null, null, null);
240 private void RegisterCommandTarget()
242 if (null == provider
)
243 throw new InvalidOperationException();
245 IVsRegisterPriorityCommandTarget registerCommandTarget
= (IVsRegisterPriorityCommandTarget
)provider
.GetService(typeof(SVsRegisterPriorityCommandTarget
));
246 if (null != registerCommandTarget
)
247 NativeMethods
.ThrowOnFailure(
248 registerCommandTarget
.RegisterPriorityCommandTarget(
250 (IOleCommandTarget
)commandService
,
251 out commandTargetCookie
));
254 private void PrivateInit(IServiceProvider sp
, Control contained
, IOleCommandTarget parentTarget
)
258 commandTargetCookie
= 0;
259 if (null == parentTarget
)
261 commandService
= new OleMenuCommandService(sp
);
265 commandService
= new OleMenuCommandService(sp
, parentTarget
);
269 // Now we have to register the IOleCommandTarget implemented by the OleCommandService
270 // as a priority command target, so it will be called by the shell.
271 RegisterCommandTarget();
274 // Set the defaults for the toolbar (empty toolbar placed at the top)
275 toolbarRect
.left
= 0;
277 toolbarRect
.right
= 0;
278 toolbarRect
.bottom
= 0;
279 toolbarCommandId
= null;
280 toolbarLocation
= VSTWT_LOCATION
.VSTWT_TOP
;
282 if (null == contained
)
284 containedForm
= null;
288 controlSize
= contained
.ClientSize
;
289 containedForm
= new WindowPaneAdapter(this, contained
);
290 this.Site
= contained
.Site
;
291 Form innerForm
= contained
as Form
;
292 if (null != innerForm
)
294 // If the contained control is a form, then copy some
295 // of its property to this one.
296 this.AcceptButton
= innerForm
.AcceptButton
;
297 this.AccessibleDefaultActionDescription
= innerForm
.AccessibleDefaultActionDescription
;
298 this.AccessibleDescription
= innerForm
.AccessibleDescription
;
299 this.AccessibleName
= innerForm
.AccessibleName
;
300 this.AccessibleRole
= innerForm
.AccessibleRole
;
301 this.AllowDrop
= innerForm
.AllowDrop
;
302 this.AllowTransparency
= innerForm
.AllowTransparency
;
303 this.AutoScaleDimensions
= innerForm
.AutoScaleDimensions
;
304 this.AutoScaleMode
= innerForm
.AutoScaleMode
;
305 this.AutoScroll
= innerForm
.AutoScroll
;
306 this.AutoScrollMargin
= innerForm
.AutoScrollMargin
;
307 this.AutoScrollMinSize
= innerForm
.AutoScrollMinSize
;
308 this.AutoScrollPosition
= innerForm
.AutoScrollPosition
;
309 this.BindingContext
= innerForm
.BindingContext
;
310 this.Bounds
= innerForm
.Bounds
;
311 this.CancelButton
= innerForm
.CancelButton
;
312 this.ContextMenu
= innerForm
.ContextMenu
;
313 this.ControlBox
= innerForm
.ControlBox
;
314 this.Cursor
= innerForm
.Cursor
;
315 this.DesktopBounds
= innerForm
.DesktopBounds
;
316 this.DesktopLocation
= innerForm
.DesktopLocation
;
317 this.Font
= innerForm
.Font
;
318 this.FormBorderStyle
= innerForm
.FormBorderStyle
;
319 this.Icon
= innerForm
.Icon
;
320 this.IsAccessible
= innerForm
.IsAccessible
;
321 this.MaximizeBox
= innerForm
.MaximizeBox
;
322 this.MaximumSize
= innerForm
.MaximumSize
;
323 this.Menu
= innerForm
.Menu
;
324 this.MinimizeBox
= innerForm
.MinimizeBox
;
325 this.MinimumSize
= innerForm
.MinimumSize
;
326 this.Opacity
= innerForm
.Opacity
;
327 this.Region
= innerForm
.Region
;
328 this.RightToLeft
= innerForm
.RightToLeft
;
329 this.ShowInTaskbar
= innerForm
.ShowInTaskbar
;
330 this.SizeGripStyle
= innerForm
.SizeGripStyle
;
331 this.StartPosition
= innerForm
.StartPosition
;
332 this.Text
= innerForm
.Text
;
333 this.TopLevel
= innerForm
.TopLevel
;
334 this.TopMost
= innerForm
.TopMost
;
335 this.TransparencyKey
= innerForm
.TransparencyKey
;
338 // At the end of the copy we have to set the properties that we want
339 // to enforse (right now only the HelpButton on the command bar).
340 this.HelpButton
= true;
342 // Set the callbacks for the events that this default implementation will handle.
343 this.Load
+= new EventHandler(FormLoad
);
344 this.Closing
+= new System
.ComponentModel
.CancelEventHandler(OnClosing
);
347 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.SetSite"]/*' />
349 /// Set the site for this window.
351 public void SetSite(IServiceProvider sp
)
353 if (null != provider
)
354 throw new InvalidOperationException();
357 RegisterCommandTarget();
360 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.Dispose"]/*' />
363 protected override void Dispose(bool disposing
)
367 // Make sure that all the resources are closed.
368 OnClosing(this, new System
.ComponentModel
.CancelEventArgs());
370 base.Dispose(disposing
);
373 private void OnClosing(object sender
, System
.ComponentModel
.CancelEventArgs e
)
375 // Close the toolbar host.
376 if (null != toolbarHost
)
378 toolbarHost
.Close(0);
381 // Close and dispose the main pane.
382 if (null != containedForm
)
384 ((IVsWindowPane
)containedForm
).ClosePane();
385 containedForm
= null;
387 // Check if we are still registered as priority command target
388 if ( (0 != commandTargetCookie
) && (null != provider
) )
390 IVsRegisterPriorityCommandTarget registerCommandTarget
= GetService(typeof(SVsRegisterPriorityCommandTarget
)) as IVsRegisterPriorityCommandTarget
;
391 if (null != registerCommandTarget
)
392 registerCommandTarget
.UnregisterPriorityCommandTarget(commandTargetCookie
);
393 commandTargetCookie
= 0;
399 object IServiceProvider
.GetService(System
.Type serviceType
)
401 if ( serviceType
.IsEquivalentTo(typeof(IVsToolWindowToolbar
)) )
404 if ( serviceType
.IsEquivalentTo(typeof(IOleCommandTarget
)) )
405 return commandService
;
407 if ( (serviceType
.IsEquivalentTo(typeof(IVsToolWindowToolbarHost
))) && (null != ToolbarHost
) )
410 return provider
.GetService(serviceType
);
413 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.ToolbarID"]/*' />
415 /// Gets or Sets the CommandID of the toolbar contained in this dialog.
417 public CommandID ToolbarID
419 get { return toolbarCommandId; }
420 set { toolbarCommandId = value; }
423 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.ToolbarLocation"]/*' />
425 /// Location of the toolbar (Top, left, right ot bottom).
427 public VSTWT_LOCATION ToolbarLocation
429 get { return toolbarLocation; }
430 set { toolbarLocation = value; }
433 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.ToolbarDropTarget"]/*' />
435 /// If the toolwindow has a ToolBar, allows intercepting drag and drop operations on the toolbar.
436 /// Otherwise this is null
438 public IDropTarget ToolbarDropTarget
440 get { return toolbarDropTarget; }
441 set { toolbarDropTarget = value; }
444 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.ToolbarHost"]/*' />
446 /// Gets the IVsToolWindowToolbarHost interface for this window.
448 public IVsToolWindowToolbarHost ToolbarHost
452 // Check if there is a cached pointer to the interface.
453 if (null != toolbarHost
)
456 // If no cached version exist, we have to get a new one
457 // from the UIShell service.
458 IVsUIShell uiShell
= (IVsUIShell
)provider
.GetService(typeof(SVsUIShell
));
459 NativeMethods
.ThrowOnFailure(
460 uiShell
.SetupToolbar(Handle
, (IVsToolWindowToolbar
)this, out toolbarHost
));
465 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.CommandService"]/*' />
467 /// Returns the command service used to check the status or execute
468 /// the toolbar's commands.
470 public IMenuCommandService CommandService
472 get { return commandService as IMenuCommandService; }
475 int IVsToolWindowToolbar
.GetBorder(RECT
[] rect
)
477 // Check that the parameter is correct.
478 if ((null == rect
) || (rect
.Length
!= 1))
479 throw new ArgumentException("rect");
481 // Return the client area of this form.
484 rect
[0].right
= this.ClientSize
.Width
;
485 rect
[0].bottom
= this.ClientSize
.Height
;
487 return NativeMethods
.S_OK
;
490 int IVsToolWindowToolbar
.SetBorderSpace(RECT
[] rect
)
492 // Check input parameter.
493 if ((null == rect
) || (rect
.Length
!= 1))
494 throw new ArgumentException("rect");
496 // Store the toolbar informations and resize the main pane to leave room
497 // for the commandbar.
498 toolbarRect
= rect
[0];
501 return NativeMethods
.S_OK
;
504 [SecurityPermission(SecurityAction
.LinkDemand
, Flags
= SecurityPermissionFlag
.UnmanagedCode
)]
505 bool IMessageFilter
.PreFilterMessage(ref Message m
)
507 if (null != ToolbarHost
)
510 int hr
= ToolbarHost
.ProcessMouseActivationModal(m
.HWnd
,(uint)m
.Msg
, (uint)m
.WParam
, (int)m
.LParam
, out lResult
);
512 if ( NativeMethods
.Failed(hr
) )
514 // ProcessMouseActivationModal returns S_FALSE to stop the message processing, but this
515 // function have to return true in this case.
516 return (hr
==NativeMethods
.S_FALSE
);
522 /// <include file='doc\DialogContainerWithToolbar.uex' path='docs/doc[@for="DialogContainerWithToolbar.ShowDialog"]/*' />
524 /// Show this window as modal dialog.
526 public new DialogResult
ShowDialog()
528 // if we don't have a service provider we can not show the dialog correctly
529 if (null == provider
)
530 throw new InvalidOperationException();
533 IMessageFilter filter
= this as IMessageFilter
;
535 // Make sure that there is non visual containment for this form
536 ShowDialogContainer dialogContainer
= null;
537 if (this.Site
== null)
539 dialogContainer
= new ShowDialogContainer((IServiceProvider
)this);
540 dialogContainer
.Add(this);
545 // This form needs to install its message filter in order to
546 // let the toolbar process the mouse events.
547 Application
.AddMessageFilter(filter
);
549 // Show the modal dialog
550 result
= base.ShowDialog();
554 if (dialogContainer
!= null)
555 dialogContainer
.Remove(this);
556 Application
.RemoveMessageFilter(filter
);
562 private void ResizePane()
564 // Get the size of the window.
565 System
.Drawing
.Size mySize
= this.ClientSize
;
567 // toolbarRect is not a real rectangle, it store the space that we have
568 // to free at the left, top, right and bottom of this form for the toolbar.
569 // So we have to move the main pane out of the way.
570 int x
= toolbarRect
.left
;
571 int y
= toolbarRect
.top
;
572 int width
= mySize
.Width
- toolbarRect
.left
- toolbarRect
.right
;
573 int height
= mySize
.Height
- toolbarRect
.top
- toolbarRect
.bottom
;
575 containedForm
.Move(x
, y
, height
, width
);
578 private void ResizeForm(object sender
, EventArgs e
)
581 if (ToolbarHost
!= null)
582 ToolbarHost
.BorderChanged();
585 private void FormLoad(object sender
, EventArgs e
)
590 if (null == containedForm
)
592 // Handle the case that the class was constructed with the parameterless
593 // constructor, so no container control is created.
594 // In this case we have to create a new control that will contain all the
595 // controls contained by this form and use it to create the window pane.
596 Control paneControl
= new UserControl();
597 while (this.Controls
.Count
> 0)
599 Control ctl
= this.Controls
[0];
600 ctl
.Parent
= paneControl
;
602 containedForm
= new WindowPaneAdapter(this, paneControl
);
603 controlSize
= this.ClientSize
;
606 System
.Drawing
.Size mySize
= this.ClientSize
;
608 // Check if this window has a toolbar.
609 if (null != toolbarCommandId
)
611 Guid toolbarCommandSet
= toolbarCommandId
.Guid
;
612 IVsToolWindowToolbarHost2 toolBarHost2
= (IVsToolWindowToolbarHost2
)ToolbarHost
;
613 NativeMethods
.ThrowOnFailure(
614 toolBarHost2
.AddToolbar2(toolbarLocation
, ref toolbarCommandSet
, (uint)toolbarCommandId
.ID
, toolbarDropTarget
));
615 NativeMethods
.ThrowOnFailure(ToolbarHost
.Show(0));
616 NativeMethods
.ThrowOnFailure(ToolbarHost
.ForceUpdateUI());
619 // Now we have to resize the form to make room for the toolbar.
620 mySize
.Width
= controlSize
.Width
+ toolbarRect
.left
+ toolbarRect
.right
;
621 mySize
.Height
= controlSize
.Height
+ toolbarRect
.top
+ toolbarRect
.bottom
;
622 this.ClientSize
= mySize
;
624 // Find the coordinate of the main pane.
625 int x
= toolbarRect
.left
;
626 int y
= toolbarRect
.top
;
627 int width
= mySize
.Width
- toolbarRect
.left
- toolbarRect
.right
;
628 int height
= mySize
.Height
- toolbarRect
.top
- toolbarRect
.bottom
;
630 // Make sure that the pane is created.
631 containedForm
.Create(x
, y
, height
, width
);
632 // Set the focus to the control
633 containedForm
.Focus();
635 // Install the handler for the resize.
636 this.Resize
+= new EventHandler(ResizeForm
);