Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VS 2013 Update #6

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
/*/*.csproj.user
/*/bin/*
/*/obj/*
/*/StyleCop.cache
/*/StyleCop.cache
Whut.AttachTo.sln.GhostDoc.xml
15 changes: 8 additions & 7 deletions Whut.AttachTo/AttachTo.vsct
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
defining some of the constants that we will use inside the file. -->

<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
<Extern href="stdidcmd.h"/>
<Extern href="stdidcmd.h" />

<!--This header contains the command ids for the menus provided by the shell. -->
<Extern href="vsshlids.h"/>
<Extern href="vsshlids.h" />

<!--Definition of some VSCT specific constants. In this sample we use it for the IDs inside the guidOfficeIcon group. -->
<Extern href="msobtnid.h"/>
<!--<Extern href="msobtnid.h" xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" />-->

<!--The Commands section is where we the commands, menus and menu groups are defined.
This section uses a Guid to identify the package that provides the command defined inside it. -->
Expand All @@ -40,7 +40,7 @@
must be a menu. -->
<Groups>
<Group guid="guidAttachToCmdSet" id="WhutAttachToMenuGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS" />
</Group>
</Groups>

Expand Down Expand Up @@ -74,7 +74,7 @@
<ButtonText>Attach to IIS Express</ButtonText>
</Strings>
</Button>

<Button guid="guidAttachToCmdSet" id="cmdidWhutAttachToNUnit" priority="0x0100" type="Button">
<Parent guid="guidAttachToCmdSet" id="WhutAttachToMenuGroup" />
<Icon guid="guidImages" id="bmpPic1" />
Expand All @@ -93,7 +93,7 @@
bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
inside a button definition. An important aspect of this declaration is that the element id
must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
<Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
<Bitmap guid="guidImages" href="Resources\Images.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows" />
</Bitmaps>
</Commands>

Expand All @@ -109,12 +109,13 @@
<IDSymbol name="cmdidWhutAttachToNUnit" value="0x0102" />
</GuidSymbol>

<GuidSymbol name="guidImages" value="{7cecfc21-6262-422a-93dd-223db26a763c}" >
<GuidSymbol name="guidImages" value="{7cecfc21-6262-422a-93dd-223db26a763c}">
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
<IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>
</Symbols>
</CommandTable>
144 changes: 119 additions & 25 deletions Whut.AttachTo/AttachToPackage.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,51 @@
using System;
using System.ComponentModel.Design;
using System.Linq;
using System.Runtime.InteropServices;
using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using PostSharp.Patterns.Diagnostics;
using PostSharp.Extensibility;
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AttachToPackage.cs" company="">
//
// </copyright>
// <summary>
// This is the class that implements the package exposed by this assembly.
// The minimum requirement for a class to be considered a valid package for Visual Studio
// is to implement the IVsPackage interface and register itself with the shell.
// This package uses the helper classes defined inside the Managed Package Framework (MPF)
// to do it: it derives from the Package class that provides the implementation of the
// IVsPackage interface and uses the registration attributes defined in the framework to
// register itself and its components with the shell.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Whut.AttachTo
{
//// This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is a package.
using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;

using EnvDTE;

using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;

using Process = EnvDTE.Process;

/// <summary>
/// This is the class that implements the package exposed by this assembly.
/// The minimum requirement for a class to be considered a valid package for Visual Studio
/// is to implement the IVsPackage interface and register itself with the shell.
/// This package uses the helper classes defined inside the Managed Package Framework (MPF)
/// to do it: it derives from the Package class that provides the implementation of the
/// IVsPackage interface and uses the registration attributes defined in the framework to
/// register itself and its components with the shell.
/// </summary>
//// This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
//// a package.
[PackageRegistration(UseManagedResourcesOnly = true)]
//// This attribute is used to register the informations needed to show the this package in the Help/About dialog of Visual Studio.
//// This attribute is used to register the information needed to show this package
//// in the Help/About dialog of Visual Studio.
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
//// This attribute is needed to let the shell know that this package exposes some menus.
[ProvideMenuResource("Menus.ctmenu", 1)]
Expand All @@ -20,34 +55,93 @@ namespace Whut.AttachTo
[ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string)]
public sealed class AttachToPackage : Package
{
#region Methods

/// <summary>
/// Initialization of the package; this method is called right after the package is sited, so this is the place
/// where you can put all the initialization code that rely on services provided by VisualStudio.
/// </summary>
protected override void Initialize()
{
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this));
base.Initialize();

OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
// Add our command handlers for menu (commands must exist in the .vsct file)
var oleMenuCommandService = this.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (oleMenuCommandService == null)
{
return;
}

// Create the command for the menu item.
this.AddAttachToCommand(
oleMenuCommandService,
PkgCmdIDList.cmdidWhutAttachToIIS,
gop => gop.ShowAttachToIIS,
"w3wp.exe");

this.AddAttachToCommand(mcs, PkgCmdIDList.cmdidWhutAttachToIIS, gop => gop.ShowAttachToIIS, "w3wp.exe");
this.AddAttachToCommand(mcs, PkgCmdIDList.cmdidWhutAttachToIISExpress, gop => gop.ShowAttachToIISExpress, "iisexpress.exe");
this.AddAttachToCommand(mcs, PkgCmdIDList.cmdidWhutAttachToNUnit, gop => gop.ShowAttachToNUnit, "nunit-agent.exe", "nunit.exe", "nunit-console.exe", "nunit-agent-x86.exe", "nunit-x86.exe", "nunit-console-x86.exe");
this.AddAttachToCommand(
oleMenuCommandService,
PkgCmdIDList.cmdidWhutAttachToIISExpress,
gop => gop.ShowAttachToIISExpress,
"iisexpress.exe");

this.AddAttachToCommand(
oleMenuCommandService,
PkgCmdIDList.cmdidWhutAttachToNUnit,
gop => gop.ShowAttachToNUnit,
"nunit-agent.exe",
"nunit.exe",
"nunit-console.exe",
"nunit-agent-x86.exe",
"nunit-x86.exe",
"nunit-console-x86.exe");
}

private void AddAttachToCommand(OleMenuCommandService mcs, uint commandId, Func<GeneralOptionsPage, bool> isVisible, params string[] programsToAttach)
/// <summary>
/// Adds the attach automatic command.
/// </summary>
/// <param name="oleMenuCommandService">
/// The MCS.
/// </param>
/// <param name="commandId">
/// The command unique identifier.
/// </param>
/// <param name="isVisible">
/// The is visible.
/// </param>
/// <param name="programsToAttach">
/// The programs automatic attach.
/// </param>
private void AddAttachToCommand(
IMenuCommandService oleMenuCommandService,
uint commandId,
Func<GeneralOptionsPage, bool> isVisible,
params string[] programsToAttach)
{
OleMenuCommand menuItemCommand = new OleMenuCommand(
delegate(object sender, EventArgs e)
{
DTE dte = (DTE)this.GetService(typeof(DTE));
foreach (Process process in dte.Debugger.LocalProcesses)
Contract.Requires<ArgumentNullException>(oleMenuCommandService != null);

var menuItemCommand = new OleMenuCommand(
delegate
{
if (programsToAttach.Any(p => process.Name.EndsWith(p)))
// ReSharper disable once IdentifierTypo
var dte = (DTE)this.GetService(typeof(DTE));
foreach (var process in
dte.Debugger.LocalProcesses.Cast<Process>()
.Where(process => programsToAttach.Any(p => process.Name.EndsWith(p))))
{
process.Attach();
}
}
},
},
new CommandID(GuidList.guidAttachToCmdSet, (int)commandId));
menuItemCommand.BeforeQueryStatus += (s, e) => menuItemCommand.Visible = isVisible((GeneralOptionsPage)this.GetDialogPage(typeof(GeneralOptionsPage)));
mcs.AddCommand(menuItemCommand);

menuItemCommand.BeforeQueryStatus +=
(s, e) =>
menuItemCommand.Visible = isVisible((GeneralOptionsPage)this.GetDialogPage(typeof(GeneralOptionsPage)));

oleMenuCommandService.AddCommand(menuItemCommand);
}

#endregion
}
}
}
133 changes: 133 additions & 0 deletions Whut.AttachTo/Attributes/TraceAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
namespace Whut.AttachTo.Attributes
{
using System;
using System.Diagnostics;
using System.Reflection;
using System.Text;

using PostSharp.Aspects;

/// <summary>
/// The trace attribute class.
/// </summary>
[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
#region Fields

/// <summary>
/// The method name.
/// </summary>
private string methodName = "UnknownMethodName";

#endregion

#region Public Methods and Operators

/// <summary>
/// Method invoked at build time to initialize the instance fields of the current aspect. This method is invoked
/// before any other build-time method.
/// </summary>
/// <param name="method">
/// Method to which the current aspect is applied
/// </param>
/// <param name="aspectInfo">
/// Reserved for future usage.
/// </param>
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
base.CompileTimeInitialize(method, aspectInfo);

if (method.DeclaringType != null)
{
this.methodName = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name);
}
}

/// <summary>
/// Method executed <b>before</b> the body of methods to which this aspect is applied.
/// </summary>
/// <param name="args">
/// Event arguments specifying which method
/// is being executed, which are its arguments, and how should the execution continue
/// after the execution of
/// <see cref="M:PostSharp.Aspects.IOnMethodBoundaryAspect.OnEntry(PostSharp.Aspects.MethodExecutionArgs)"/>.
/// </param>
public override void OnEntry(MethodExecutionArgs args)
{
base.OnEntry(args);

Trace.TraceInformation("{0}: Enter", this.methodName);
Trace.Indent();
}

/// <summary>
/// Method executed <b>after</b> the body of methods to which this aspect is applied,
/// in case that the method resulted with an exception.
/// </summary>
/// <param name="args">
/// Event arguments specifying which method is being executed and which are its arguments.
/// </param>
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);

var stringBuilder = new StringBuilder(1024);

stringBuilder.AppendFormat("{0}(", this.methodName);
var instance = args.Instance;
if (instance != null)
{
stringBuilder.AppendFormat("this={0}", instance);
if (args.Arguments.Count > 0)
{
stringBuilder.Append("; ");
}
}

for (var i = 0; i < args.Arguments.Count; i++)
{
if (i > 0)
{
stringBuilder.Append(", ");
}

stringBuilder.Append(args.Arguments.GetArgument(i) ?? "null");
}

var guid = Guid.NewGuid();

stringBuilder.AppendFormat(
"): Exception {0} - {1}: {2}",
guid,
args.Exception.GetType().Name,
args.Exception.Message);

Trace.Unindent();
Trace.TraceError(stringBuilder.ToString());

throw new ApplicationException(
string.Format(
"An internal exception has occurred. Use the id {0} for further reference to this issue.",
guid));
}

/// <summary>
/// Method executed <b>after</b> the body of methods to which this aspect is applied,
/// but only when the method successfully returns (i.e. when no exception flies out
/// the method.).
/// </summary>
/// <param name="args">
/// Event arguments specifying which method is being executed and which are its arguments.
/// </param>
public override void OnSuccess(MethodExecutionArgs args)
{
base.OnSuccess(args);

Trace.Unindent();
Trace.TraceInformation("{0}: Success", this.methodName);
}

#endregion
}
}
Loading