added some development tools
[windows-sources.git] / developer / VSSDK / VisualStudioIntegration / Common / Source / CSharp / Shell / WindowPane.cs
blob6fc7a45c857eff97ea8b8ee328e6cfd323bd4985
1 //------------------------------------------------------------------------------
2 // <copyright file="WindowPane.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 namespace Microsoft.VisualStudio.Shell {
9 using Microsoft.VisualStudio.OLE.Interop;
10 using Microsoft.VisualStudio.Shell.Interop;
11 using Microsoft.Win32;
12 using System;
13 using System.Collections;
14 using System.ComponentModel;
15 using System.ComponentModel.Design;
16 using System.Diagnostics;
17 using System.Diagnostics.CodeAnalysis;
18 using System.Drawing;
19 using System.Runtime.InteropServices;
20 using System.Windows.Forms;
22 using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
23 using IServiceProvider = System.IServiceProvider;
25 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane"]' />
26 /// <devdoc>
27 /// This is a quick way to implement a tool window pane. This class
28 /// implements IVsWindowPane; you must provide an implementation of an
29 /// object that returns an IWin32Window, however. In addition to
30 /// IVsWindowPane this object implements IOleCommandTarget, mapping
31 /// it to IMenuCommandService and IObjectWithSite, mapping the site
32 /// to services that can be querried through its protected GetService
33 /// method.
34 /// </devdoc>
35 [System.Runtime.InteropServices.ComVisible(true)]
36 public abstract class WindowPane :
38 IVsWindowPane,
39 IOleCommandTarget,
40 IVsBroadcastMessageEvents,
41 IServiceProvider,
42 IDisposable {
44 private IServiceProvider _parentProvider;
45 private ServiceProvider _provider;
46 private IVsShell _vsShell;
47 private uint _broadcastEventCookie;
49 private IMenuCommandService _commandService;
50 private HelpService _helpService;
52 private bool _zombie = false;
54 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.WindowPane"]' />
55 /// <devdoc>
56 /// Creates a new window pane. The window pane can accept a service provider
57 /// to use when resolving services. This provider can be null.
58 /// </devdoc>
59 protected WindowPane(IServiceProvider provider) {
60 _parentProvider = provider;
63 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.Window"]' />
64 /// <devdoc>
65 /// Retrieves the window associated with this window pane.
66 /// </devdoc>
67 public abstract IWin32Window Window { get; }
69 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.Dispose"]' />
70 /// <devdoc>
71 /// Can be called to dispose this editing window.
72 /// </devdoc>
73 public void Dispose() {
74 Dispose(true);
77 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.Dispose1"]' />
78 /// <devdoc>
79 /// Called when this window pane is being disposed.
80 /// </devdoc>
81 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
82 protected virtual void Dispose(bool disposing) {
84 if (disposing) {
86 if (_vsShell != null) {
87 try {
88 // Don't check for return code because here we can't do anything in case of failure.
89 _vsShell.UnadviseBroadcastMessages(_broadcastEventCookie);
90 } catch (Exception) { /* do nothing */ }
91 _vsShell = null;
92 _broadcastEventCookie = 0;
95 IWin32Window window = Window;
96 if (window is IDisposable) {
97 try {
98 ((IDisposable)window).Dispose();
99 } catch (Exception) {
100 Debug.Fail("Failed to dispose window");
103 window = null;
105 if (_commandService != null && _commandService is IDisposable) {
106 try {
107 ((IDisposable)_commandService).Dispose();
108 } catch (Exception) {
109 Debug.Fail("Failed to dispose command service");
112 _commandService = null;
114 if (_parentProvider != null)
115 _parentProvider = null;
117 if (_helpService != null)
118 _helpService = null;
120 // Do not clear _provider. SetSite will do it for us.
122 _zombie = true;
126 /// <devdoc>
127 /// This is a separate method so the jitter doesn't see MenuCommandService (from system.design.dll) in
128 /// the GetService call and load the assembly.
129 /// </devdoc>
130 private void EnsureCommandService() {
131 if (_commandService == null) {
132 _commandService = new OleMenuCommandService(this);
136 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.GetService"]' />
137 /// <devdoc>
138 /// Maps to IServiceProvider for service routing.
139 /// </devdoc>
140 protected virtual object GetService(Type serviceType) {
142 if (_zombie)
144 Debug.Fail("GetService called after WindowPane was zombied");
145 return null;
148 if (serviceType == null) {
149 throw new ArgumentNullException("serviceType");
152 // We provide IMenuCommandService, so we will
153 // demand create it. MenuCommandService also
154 // implements IOleCommandTarget, but unless
155 // someone requested IMenuCommandService no commands
156 // will exist, so we don't demand create for
157 // IOleCommandTarget
159 if (serviceType == typeof(IMenuCommandService)) {
160 EnsureCommandService();
161 return _commandService;
163 else if (serviceType == typeof(IOleCommandTarget)) {
164 return _commandService;
166 else if (serviceType == typeof(IHelpService)) {
167 if (_helpService == null) {
168 _helpService = new HelpService(this);
170 return _helpService;
173 if (_provider != null) {
174 object service = _provider.GetService(serviceType);
175 if (service != null) {
176 return service;
180 if (_parentProvider != null) {
181 return _parentProvider.GetService(serviceType);
184 return null;
187 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.Initialize"]' />
188 /// <devdoc>
189 /// This method is called after the window pane has been sited. Any initialization
190 /// that requires window frame services from VS can be done by overriding this
191 /// method.
192 /// </devdoc>
193 protected virtual void Initialize() {
196 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.OnClose"]/*' />
197 /// <devdoc>
198 /// The OnClose method is called in response to the ClosePane method on
199 /// IVsWindowPane. The default implementation calls Dispose();
200 /// </devdoc>
201 protected virtual void OnClose() {
202 Dispose();
205 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.OnCreate"]/*' />
206 /// <devdoc>
207 /// The OnCreate method is called during the CreatePaneWindow method of
208 /// IVsWindowPane. This provides a handy hook for knowing when VS wants
209 /// the window. The default implementation does nothing.
210 /// </devdoc>
211 protected virtual void OnCreate() {
214 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.PreProcessMessage"]' />
215 /// <devdoc>
216 /// This method will be called to pre-process keyboard
217 /// messages before VS handles them. It is directly
218 /// attached to IVsWindowPane::TranslateAccellerator.
219 /// The default implementation calls the PreProcessMessage
220 /// method on a Windows Forms control. You may override this if your
221 /// window pane is not based on Windows Forms.
222 /// Arguments and return values are the
223 /// same as for Windows Forms: return true if you handled
224 /// the message, false if you want the default processing
225 /// to occur.
226 /// </devdoc>
227 protected virtual bool PreProcessMessage(ref Message m) {
228 Control c = Control.FromChildHandle(m.HWnd);
229 if (c != null) {
230 return c.PreProcessControlMessage(ref m) == PreProcessControlState.MessageProcessed;
232 else {
233 return false;
237 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IOleCommandTarget.Exec"]/*' />
238 /// <internalonly/>
239 /// <devdoc>
240 /// This is called by Visual Studio when the user has requested to execute a particular
241 /// command. There is no need to override this method. If you need access to menu
242 /// commands use IMenuCommandService.
243 /// </devdoc>
244 int IOleCommandTarget.Exec(ref Guid guidGroup, uint nCmdId, uint nCmdExcept, IntPtr pIn, IntPtr vOut) {
246 // Always redirect through GetService for this. That way outside users can replace
247 // it.
249 IOleCommandTarget cmdTarget = GetService(typeof(IOleCommandTarget)) as IOleCommandTarget;
250 if (cmdTarget != null) {
251 return cmdTarget.Exec(ref guidGroup, nCmdId, nCmdExcept, pIn, vOut);
253 else {
254 return NativeMethods.OLECMDERR_E_NOTSUPPORTED;
258 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IOleCommandTarget.QueryStatus"]/*' />
259 /// <internalonly/>
260 /// <devdoc>
261 /// This is called by Visual Studio when it needs the status of our menu commands. There
262 /// is no need to override this method. If you need access to menu commands use
263 /// IMenuCommandService.
264 /// </devdoc>
265 int IOleCommandTarget.QueryStatus(ref Guid guidGroup, uint nCmdId, OLECMD[] oleCmd, IntPtr oleText) {
267 // Always redirect through GetService for this. That way outside users can replace
268 // it.
270 IOleCommandTarget cmdTarget = GetService(typeof(IOleCommandTarget)) as IOleCommandTarget;
271 if (cmdTarget != null) {
272 return cmdTarget.QueryStatus(ref guidGroup, nCmdId, oleCmd, oleText);
274 else {
275 return NativeMethods.OLECMDERR_E_NOTSUPPORTED;
279 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IServiceProvider.GetService"]/*' />
280 /// <internalonly/>
281 /// <devdoc>
282 /// IServiceProvider implementation.
283 /// </devdoc>
284 object IServiceProvider.GetService(Type serviceType) {
285 return GetService(serviceType);
288 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsBroadcastMessageEvents.OnBroadcastMessage"]/*' />
289 /// <internalonly/>
290 /// <devdoc>
291 /// Receives broadcast messages from the shell
292 /// </devdoc>
293 int IVsBroadcastMessageEvents.OnBroadcastMessage(uint msg, IntPtr wParam, IntPtr lParam) {
294 int hr = NativeMethods.S_OK;
295 IntPtr hwnd = Window.Handle;
296 bool result = UnsafeNativeMethods.PostMessage(hwnd, (int)msg, wParam, wParam);
297 if ( !result )
298 hr = NativeMethods.E_FAIL;
299 return hr;
302 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.ClosePane"]/*' />
303 /// <internalonly/>
304 /// <devdoc>
305 /// IVsWindowPane implementation.
306 /// </devdoc>
307 int IVsWindowPane.ClosePane() {
309 if (_vsShell != null) {
310 NativeMethods.ThrowOnFailure(_vsShell.UnadviseBroadcastMessages(_broadcastEventCookie));
311 _vsShell = null;
312 _broadcastEventCookie = 0;
315 OnClose();
316 return NativeMethods.S_OK;
319 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.CreatePaneWindow"]/*' />
320 /// <internalonly/>
321 /// <devdoc>
322 /// IVsWindowPane implementation.
323 /// </devdoc>
324 int IVsWindowPane.CreatePaneWindow(IntPtr hwndParent, int x, int y, int cx, int cy, out IntPtr pane) {
326 OnCreate();
327 IntPtr hwnd = Window.Handle;
328 int style = (int)UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_STYLE);
330 // set up the required styles of an IVsWindowPane
331 style |= (NativeMethods.WS_CLIPSIBLINGS | NativeMethods.WS_CHILD | NativeMethods.WS_VISIBLE);
332 style &= ~(NativeMethods.WS_POPUP |
333 NativeMethods.WS_MINIMIZE |
334 NativeMethods.WS_MAXIMIZE |
335 NativeMethods.WS_DLGFRAME |
336 NativeMethods.WS_SYSMENU |
337 NativeMethods.WS_THICKFRAME |
338 NativeMethods.WS_MINIMIZEBOX |
339 NativeMethods.WS_MAXIMIZEBOX);
341 UnsafeNativeMethods.SetWindowLong(hwnd, NativeMethods.GWL_STYLE, (IntPtr)style);
343 style = (int)UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_EXSTYLE);
345 style &= ~(NativeMethods.WS_EX_DLGMODALFRAME |
346 NativeMethods.WS_EX_NOPARENTNOTIFY |
347 NativeMethods.WS_EX_TOPMOST |
348 NativeMethods.WS_EX_MDICHILD |
349 NativeMethods.WS_EX_TOOLWINDOW |
350 NativeMethods.WS_EX_CONTEXTHELP |
351 NativeMethods.WS_EX_APPWINDOW);
353 UnsafeNativeMethods.SetWindowLong(hwnd, NativeMethods.GWL_EXSTYLE, (IntPtr)style);
354 UnsafeNativeMethods.SetParent(hwnd, (IntPtr)hwndParent);
355 UnsafeNativeMethods.SetWindowPos(hwnd, IntPtr.Zero, x, y, cx, cy, NativeMethods.SWP_NOZORDER | NativeMethods.SWP_NOACTIVATE);
356 UnsafeNativeMethods.ShowWindow(hwnd, NativeMethods.SW_SHOWNORMAL);
358 // Sync broadcast events so we update our UI when colors/fonts change.
360 if (_vsShell == null) {
361 _vsShell = (IVsShell)GetService(typeof(SVsShell));
362 if (_vsShell != null) {
363 NativeMethods.ThrowOnFailure(_vsShell.AdviseBroadcastMessages(this, out _broadcastEventCookie));
367 pane = hwnd;
368 return NativeMethods.S_OK;
371 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.GetDefaultSize"]/*' />
372 /// <internalonly/>
373 /// <devdoc>
374 /// IVsWindowPane implementation.
375 /// </devdoc>
376 int IVsWindowPane.GetDefaultSize(SIZE[] size) {
377 return NativeMethods.E_NOTIMPL;
380 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.LoadViewState"]/*' />
381 /// <internalonly/>
382 /// <devdoc>
383 /// IVsWindowPane implementation.
384 /// </devdoc>
385 int IVsWindowPane.LoadViewState(IStream pstream) {
386 Marshal.ReleaseComObject(pstream);
387 return NativeMethods.E_NOTIMPL;
390 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.SaveViewState"]/*' />
391 /// <internalonly/>
392 /// <devdoc>
393 /// IVsWindowPane implementation.
394 /// </devdoc>
395 int IVsWindowPane.SaveViewState(IStream pstream) {
396 Marshal.ReleaseComObject(pstream);
397 return NativeMethods.E_NOTIMPL;
400 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.SetSite"]/*' />
401 /// <internalonly/>
402 /// <devdoc>
403 /// IVsWindowPane implementation.
404 /// </devdoc>
405 int IVsWindowPane.SetSite(IOleServiceProvider p) {
407 // The siting mechanism works as follows: If the
408 // parent provider provides ServiceProviderHierarchy
409 // as a service we will insert our service provider in
410 // the WindowPaneSite slot of the hierarchy.
411 // If, however, it does not provide
412 // this service, we will create a new
413 // ServiceProvider that will be used to resolve
414 // services through this site.
416 if (_provider != null) {
417 _provider.Dispose();
418 _provider = null;
421 IObjectWithSite ows = GetService(typeof(IObjectWithSite)) as IObjectWithSite;
422 ServiceProviderHierarchy serviceHierarchy = GetService(typeof(ServiceProviderHierarchy)) as ServiceProviderHierarchy;
423 if (serviceHierarchy != null) {
424 ServiceProvider sp = (p == null ? null : new ServiceProvider(p));
425 serviceHierarchy[ServiceProviderHierarchyOrder.WindowPaneSite] = sp;
427 else if (ows != null) {
428 ows.SetSite(p);
430 else {
431 if (p != null) {
432 _provider = new ServiceProvider(p);
436 if (p != null) {
437 Initialize();
439 return NativeMethods.S_OK;
442 /// <include file='doc\WindowPane.uex' path='docs/doc[@for="WindowPane.IVsWindowPane.TranslateAccelerator"]/*' />
443 /// <internalonly/>
444 /// <devdoc>
445 /// IVsWindowPane implementation.
446 /// </devdoc>
447 int IVsWindowPane.TranslateAccelerator(Microsoft.VisualStudio.OLE.Interop.MSG[] msg) {
448 Message m = Message.Create(msg[0].hwnd, (int)msg[0].message, msg[0].wParam, msg[0].lParam);
449 bool eat = PreProcessMessage(ref m);
451 msg[0].message = (uint)m.Msg;
452 msg[0].wParam = m.WParam;
453 msg[0].lParam = m.LParam;
455 if (eat) {
456 return NativeMethods.S_OK;
458 else {
459 return NativeMethods.E_FAIL;