├── .gitignore
├── DebugSingleThread.sln
├── DebugSingleThread
├── DebugSingleThread.csproj
├── DebugSingleThread.csproj.user
├── Properties
│ └── AssemblyInfo.cs
└── source.extension.vsixmanifest
├── DebugSingleThread2022
├── DebugSingleThread2022.csproj
├── Properties
│ └── AssemblyInfo.cs
└── source.extension.vsixmanifest
├── DebugSingleThreadShared
├── DebugSingleThreadPackage.cs
├── DebugSingleThreadShared.projitems
├── DebugSingleThreadShared.shproj
├── GlobalSuppressions.cs
├── Guids.cs
├── MyCommand.cs
└── PkgCmdID.cs
├── DebugSingleThreadSharedFolder
├── Assets
│ ├── Icon.png
│ ├── Images_32bit.psd
│ ├── flake.png
│ ├── image1.png
│ └── image2.png
├── DebugSingleThread.vsct
├── Icon.png
├── Images_32bit.png
├── Key.snk
├── License.txt
└── Screenshot.png
├── LICENSE.txt
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs/
2 | *.suo
3 | *.csproj.user
4 | *.bak
5 | [Bb]in
6 | obj/
7 | [Rr]elease*/
8 | _ReSharper*/
9 | [Tt]humbs.db
10 | [Tt]est[Rr]esult*
11 | [Bb]uild[Ll]og.*
12 | *.[Pp]ublish.xml
13 | *.resharper
14 | var/
15 | *.sln.ide
16 | Reviews
17 | packages/
--------------------------------------------------------------------------------
/DebugSingleThread.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebugSingleThread", "DebugSingleThread\DebugSingleThread.csproj", "{78F93759-FEFC-4E82-A3EB-A46F5D93875F}"
7 | EndProject
8 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "DebugSingleThreadShared", "DebugSingleThreadShared\DebugSingleThreadShared.shproj", "{C6A85F7F-C9C7-4EBC-A727-EDF438675745}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebugSingleThread2022", "DebugSingleThread2022\DebugSingleThread2022.csproj", "{F11AAC77-729B-44DD-BBC4-6011B9066283}"
11 | EndProject
12 | Global
13 | GlobalSection(SharedMSBuildProjectFiles) = preSolution
14 | DebugSingleThreadShared\DebugSingleThreadShared.projitems*{78f93759-fefc-4e82-a3eb-a46f5d93875f}*SharedItemsImports = 4
15 | DebugSingleThreadShared\DebugSingleThreadShared.projitems*{c6a85f7f-c9c7-4ebc-a727-edf438675745}*SharedItemsImports = 13
16 | DebugSingleThreadShared\DebugSingleThreadShared.projitems*{f11aac77-729b-44dd-bbc4-6011b9066283}*SharedItemsImports = 4
17 | EndGlobalSection
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Debug|x86 = Debug|x86
21 | Release|Any CPU = Release|Any CPU
22 | Release|x86 = Release|x86
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Debug|x86.ActiveCfg = Debug|x86
28 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Debug|x86.Build.0 = Debug|x86
29 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Release|x86.ActiveCfg = Release|x86
32 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}.Release|x86.Build.0 = Release|x86
33 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Debug|x86.ActiveCfg = Debug|x86
36 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Debug|x86.Build.0 = Debug|x86
37 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Release|Any CPU.Build.0 = Release|Any CPU
39 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Release|x86.ActiveCfg = Release|x86
40 | {F11AAC77-729B-44DD-BBC4-6011B9066283}.Release|x86.Build.0 = Release|x86
41 | EndGlobalSection
42 | GlobalSection(SolutionProperties) = preSolution
43 | HideSolutionNode = FALSE
44 | EndGlobalSection
45 | GlobalSection(ExtensibilityGlobals) = postSolution
46 | SolutionGuid = {A731CA39-9077-445B-9839-028241FF321E}
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/DebugSingleThread/DebugSingleThread.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 15.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 |
7 | publish\
8 | true
9 | Disk
10 | false
11 | Foreground
12 | 7
13 | Days
14 | false
15 | false
16 | true
17 | 0
18 | 1.0.0.%2a
19 | false
20 | false
21 | true
22 |
23 |
24 | true
25 |
26 |
27 | ..\DebugSingleThreadSharedFolder\Key.snk
28 |
29 |
30 | true
31 |
32 |
33 |
34 | Debug
35 | AnyCPU
36 | 2.0
37 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
38 | {78F93759-FEFC-4E82-A3EB-A46F5D93875F}
39 | Library
40 | Properties
41 | ErwinMayerLabs.DebugSingleThread
42 | DebugSingleThread
43 | v4.6
44 | true
45 | true
46 | true
47 | false
48 | false
49 | true
50 | true
51 | Program
52 | $(DevEnvDir)devenv.exe
53 | /rootsuffix Exp
54 |
55 |
56 | true
57 | full
58 | false
59 | bin\Debug\
60 | DEBUG;TRACE
61 | prompt
62 | 4
63 |
64 |
65 | pdbonly
66 | true
67 | bin\Release\
68 | TRACE
69 | prompt
70 | 4
71 | false
72 |
73 |
74 |
75 |
76 |
77 |
78 | Key.snk
79 |
80 |
81 | Designer
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | False
94 | Microsoft .NET Framework 4.6.2 %28x86 and x64%29
95 | true
96 |
97 |
98 | False
99 | .NET Framework 3.5 SP1
100 | false
101 |
102 |
103 |
104 |
105 | 16.10.10
106 | runtime; build; native; contentfiles; analyzers; buildtransitive
107 | all
108 |
109 |
110 | 14.3.25407
111 |
112 |
113 | 10.0.4
114 |
115 |
116 |
117 |
118 | DebugSingleThread.vsct
119 | Menus.ctmenu
120 | Designer
121 |
122 |
123 | Screenshot.png
124 | true
125 |
126 |
127 | Icon.png
128 | true
129 |
130 |
131 | Images_32bit.png
132 |
133 |
134 | License.txt
135 | true
136 |
137 |
138 |
139 |
140 |
141 |
142 | if "$(ConfigurationName)" neq "Release" (
143 | exit /b 0
144 | )
145 |
146 | if not exist "$(SolutionDir)Releases\" (
147 | mkdir "$(SolutionDir)Releases\"
148 | if errorlevel 1 goto Error
149 | )
150 |
151 | copy /Y "$(TargetDir)$(TargetName).vsix" "$(SolutionDir)Releases\$(TargetName)2019 (new).vsix"
152 | if errorlevel 1 goto Error
153 |
154 | exit /b 0
155 |
156 | :Error
157 | exit /b 1
158 |
159 |
160 |
167 |
--------------------------------------------------------------------------------
/DebugSingleThread/DebugSingleThread.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | en-US
11 | false
12 | true
13 |
14 |
15 | C:\Program Files %28x86%29\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe
16 | 2fd9d919
17 |
18 |
--------------------------------------------------------------------------------
/DebugSingleThread/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DebugSingleThread")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Erwin Mayer Labs")]
12 | [assembly: AssemblyProduct("DebugSingleThread")]
13 | [assembly: AssemblyCopyright("")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Build and Revision Numbers
30 | // by using the '*' as shown below:
31 | // [assembly: AssemblyVersion("1.0.*")]
32 | [assembly: AssemblyVersion("2.0.0.0")]
33 | [assembly: AssemblyFileVersion("2.0.0.0")]
34 |
--------------------------------------------------------------------------------
/DebugSingleThread/source.extension.vsixmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug Single Thread
6 | This Visual Studio extension adds two shortcuts and toolbar buttons to allow developers to easily focus on single threads while debugging multi-threaded applications.
7 |
8 | It dramatically reduces the need to manually go into the Threads window to freeze/thaw all threads but the one that needs to be followed, and therefore helps improve productivity.
9 |
10 | Features:
11 | - Restrict further execution to the current thread only. Will freeze all other threads. Shortcut: CTRL+T+T or snowflake button. Click button again to thaw all other threads. Known frozen threads before the command runs (e.g. due to a breakpoint) will be remembered and not thawed. If this is not what you expect, please let me know so I can add the option to customize behavior.
12 | - Switch to the next single thread (based on ManagedID). Will change current thread and freeze all other threads. Shortcut: CTRL+T+J or Next button.
13 | https://erwinmayer.com/labs/visual-studio-2010-extension-debug-single-thread
14 | License.txt
15 | Icon.png
16 | Screenshot.png
17 | Multi-Threaded, Debugging, Single Thread, Thread Focus
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/DebugSingleThread2022/DebugSingleThread2022.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 17.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 |
7 |
8 | true
9 |
10 |
11 | ..\DebugSingleThreadSharedFolder\Key.snk
12 |
13 |
14 |
15 | Debug
16 | AnyCPU
17 | 2.0
18 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 | {F11AAC77-729B-44DD-BBC4-6011B9066283}
20 | Library
21 | Properties
22 | ErwinMayerLabs.DebugSingleThread
23 | DebugSingleThread2022
24 | v4.7.2
25 | true
26 | true
27 | true
28 | false
29 | false
30 | true
31 | true
32 | Program
33 | $(DevEnvDir)devenv.exe
34 | /rootsuffix Exp
35 |
36 |
37 | true
38 | full
39 | false
40 | bin\Debug\
41 | DEBUG;TRACE
42 | prompt
43 | 4
44 |
45 |
46 | pdbonly
47 | true
48 | bin\Release\
49 | TRACE
50 | prompt
51 | 4
52 |
53 |
54 |
55 |
56 |
57 |
58 | Key.snk
59 |
60 |
61 | Designer
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | DebugSingleThread.vsct
75 | Menus.ctmenu
76 | Designer
77 |
78 |
79 | Icon.png
80 | true
81 |
82 |
83 | Images_32bit.png
84 |
85 |
86 | License.txt
87 | true
88 |
89 |
90 | Screenshot.png
91 | true
92 |
93 |
94 |
95 |
96 |
97 |
98 | if "$(ConfigurationName)" neq "Release" (
99 | exit /b 0
100 | )
101 |
102 | if not exist "$(SolutionDir)Releases\" (
103 | mkdir "$(SolutionDir)Releases\"
104 | if errorlevel 1 goto Error
105 | )
106 |
107 | copy /Y "$(TargetDir)$(TargetName).vsix" "$(SolutionDir)Releases\$(TargetName) (new).vsix"
108 | if errorlevel 1 goto Error
109 |
110 | exit /b 0
111 |
112 | :Error
113 | exit /b 1
114 |
115 |
116 |
123 |
--------------------------------------------------------------------------------
/DebugSingleThread2022/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DebugSingleThread2022")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DebugSingleThread2022")]
13 | [assembly: AssemblyCopyright("")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Build and Revision Numbers
30 | // by using the '*' as shown below:
31 | // [assembly: AssemblyVersion("1.0.*")]
32 | [assembly: AssemblyVersion("1.0.0.0")]
33 | [assembly: AssemblyFileVersion("1.0.0.0")]
34 |
--------------------------------------------------------------------------------
/DebugSingleThread2022/source.extension.vsixmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug Single Thread
6 | This Visual Studio extension adds two shortcuts and toolbar buttons to allow developers to easily focus on single threads while debugging multi-threaded applications.
7 |
8 | It dramatically reduces the need to manually go into the Threads window to freeze/thaw all threads but the one that needs to be followed, and therefore helps improve productivity.
9 |
10 | Features:
11 | - Restrict further execution to the current thread only. Will freeze all other threads. Shortcut: CTRL+T+T or snowflake button. Click button again to thaw all other threads. Known frozen threads before the command runs (e.g. due to a breakpoint) will be remembered and not thawed. If this is not what you expect, please let me know so I can add the option to customize behavior.
12 | - Switch to the next single thread (based on ManagedID). Will change current thread and freeze all other threads. Shortcut: CTRL+T+J or Next button.
13 | https://erwinmayer.com/labs/visual-studio-2010-extension-debug-single-thread
14 | License.txt
15 | Icon.png
16 | Screenshot.png
17 | Multi-Threaded, Debugging, Single Thread, Thread Focus
18 |
19 |
20 |
21 | amd64
22 |
23 |
24 | amd64
25 |
26 |
27 | amd64
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/DebugSingleThreadShared/DebugSingleThreadPackage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio;
2 | using Microsoft.VisualStudio.Shell;
3 | using System;
4 | using System.Diagnostics;
5 | using System.Globalization;
6 | using System.Runtime.InteropServices;
7 | using System.Threading;
8 | using Task = System.Threading.Tasks.Task;
9 | /*
10 | * TODO:
11 | * - Add context menu item in the Threads window (Freeze all but this thread)
12 | * Sources:
13 | * http://msdn.microsoft.com/en-us/library/cc138589.aspx
14 | * http://msdn.microsoft.com/en-us/library/bb164715.aspx
15 | * http://findicons.com/icon/137367/flake?width=256#
16 | * http://www.iconspedia.com/icon/snow-flake.html
17 | * http://www.iconspedia.com/search/next/
18 | */
19 | namespace ErwinMayerLabs.DebugSingleThread {
20 | ///
21 | /// This is the class that implements the package exposed by this assembly.
22 | ///
23 | ///
24 | ///
25 | /// The minimum requirement for a class to be considered a valid package for Visual Studio
26 | /// is to implement the IVsPackage interface and register itself with the shell.
27 | /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
28 | /// to do it: it derives from the Package class that provides the implementation of the
29 | /// IVsPackage interface and uses the registration attributes defined in the framework to
30 | /// register itself and its components with the shell. These attributes tell the pkgdef creation
31 | /// utility what data to put into .pkgdef file.
32 | ///
33 | ///
34 | /// To get loaded into VS, the package must be referred by <Asset Type="Microsoft.VisualStudio.VsPackage" ...> in .vsixmanifest file.
35 | ///
36 | ///
37 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
38 | // This attribute is used to register the informations needed to show the this package
39 | // in the Help/About dialog of Visual Studio.
40 | [InstalledProductRegistration("#110", "#112", "2.0", IconResourceID = 400)]
41 | [ProvideAutoLoad(VSConstants.UICONTEXT.Debugging_string, PackageAutoLoadFlags.BackgroundLoad)]
42 | // This attribute is needed to let the shell know that this package exposes some menus.
43 | [ProvideMenuResource("Menus.ctmenu", 1)]
44 | [Guid(GuidList.guidDebugSingleThreadPkgString)]
45 | public sealed class DebugSingleThreadPackage : AsyncPackage {
46 | ///
47 | /// Default constructor of the package.
48 | /// Inside this method you can place any initialization code that does not require
49 | /// any Visual Studio service because at this point the package object is created but
50 | /// not sited yet inside Visual Studio environment. The place to do all the other
51 | /// initialization is the Initialize method.
52 | ///
53 | public DebugSingleThreadPackage() {
54 | Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this));
55 | }
56 |
57 | #region Package Members
58 | ///
59 | /// Initialization of the package; this method is called right after the package is sited, so this is the place
60 | /// where you can put all the initialization code that rely on services provided by VisualStudio.
61 | ///
62 | /// A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down.
63 | /// A provider for progress updates.
64 | /// A task representing the async work of package initialization, or an already completed task if there is none. Do not return null from this method.
65 | protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) {
66 | // When initialized asynchronously, the current thread may be a background thread at this point.
67 | // Do any initialization that requires the UI thread after switching to the UI thread.
68 | await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
69 | //await MyCommand.InitializeAsync(this);
70 |
71 | Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this));
72 | await MyCommand.InitializeAsync(this);
73 | }
74 |
75 | #endregion
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/DebugSingleThreadShared/DebugSingleThreadShared.projitems:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 | true
6 | c6a85f7f-c9c7-4ebc-a727-edf438675745
7 |
8 |
9 | DebugSingleThreadShared
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/DebugSingleThreadShared/DebugSingleThreadShared.shproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | c6a85f7f-c9c7-4ebc-a727-edf438675745
5 | 14.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/DebugSingleThreadShared/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project. Project-level
3 | // suppressions either have no target or are given a specific target
4 | // and scoped to a namespace, type, member, etc.
5 | //
6 | // To add a suppression to this file, right-click the message in the
7 | // Error List, point to "Suppress Message(s)", and click "In Project
8 | // Suppression File". You do not need to add suppressions to this
9 | // file manually.
10 |
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]
12 |
--------------------------------------------------------------------------------
/DebugSingleThreadShared/Guids.cs:
--------------------------------------------------------------------------------
1 | // Guids.cs
2 | // MUST match guids.h
3 | using System;
4 |
5 | namespace ErwinMayerLabs.DebugSingleThread
6 | {
7 | static class GuidList
8 | {
9 | public const string guidDebugSingleThreadPkgString = "9fb8ed8b-b44a-4076-b677-cbeb7b834afb";
10 | public const string guidDebugSingleThreadCmdSetString = "2d00031b-eb83-4527-a3d0-9e1c14c1be97";
11 |
12 | public static readonly Guid guidDebugSingleThreadCmdSet = new Guid(guidDebugSingleThreadCmdSetString);
13 | };
14 | }
--------------------------------------------------------------------------------
/DebugSingleThreadShared/MyCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.Design;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.Shell;
6 | using Task = System.Threading.Tasks.Task;
7 | using Thread = EnvDTE.Thread;
8 |
9 | namespace ErwinMayerLabs.DebugSingleThread {
10 | ///
11 | /// Command handler
12 | ///
13 | internal sealed class MyCommand {
14 | private static EnvDTE.DTE dte;
15 | private static OleMenuCommand FocusCmd;
16 | private static OleMenuCommand SwitchCmd;
17 |
18 | ///
19 | /// Initializes the singleton instance of the command.
20 | ///
21 | /// Owner package, not null.
22 | public static async Task InitializeAsync(AsyncPackage package) {
23 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
24 |
25 | //Add our command handlers for menu (commands must exist in the .vsct file)
26 | if (await package.GetServiceAsync(typeof(IMenuCommandService)) is OleMenuCommandService commandService) {
27 | // Create the command for the menu item.
28 | var menuCommandID1 = new CommandID(GuidList.guidDebugSingleThreadCmdSet, (int)PkgCmdIDList.FocusOnCurrentThreadCmd);
29 | var menuCommandID2 = new CommandID(GuidList.guidDebugSingleThreadCmdSet, (int)PkgCmdIDList.SwitchToNextThreadCmd);
30 | FocusCmd = new OleMenuCommand(FocusOnCurrentThread, menuCommandID1);
31 | SwitchCmd = new OleMenuCommand(SwitchToNextThread, menuCommandID2);
32 | FocusCmd.BeforeQueryStatus += OnBeforeQueryStatus;
33 | SwitchCmd.BeforeQueryStatus += OnBeforeQueryStatus;
34 |
35 | commandService.AddCommand(FocusCmd);
36 | commandService.AddCommand(SwitchCmd);
37 |
38 | dte = (EnvDTE.DTE)Package.GetGlobalService(typeof(EnvDTE.DTE));
39 | OnBeforeQueryStatus(FocusCmd, null);
40 | OnBeforeQueryStatus(SwitchCmd, null);
41 | }
42 | }
43 |
44 | // Could serve to remember threads that were frozen prior to Focusing, but it is likely that users will want to discard previous freezes.
45 | // If needed, see if we can add button to remember and not touch existing frozen threads (off by default). Or check if there is a ModifierKeys upon clicking on the button.
46 | // This may not work correctly if thread IDs are recycled within a focus/unfocus session (should be quite unlikely though, no easy workaround beside not remembering previously frozen threads at all).
47 | private static HashSet IgnoredThreads = new HashSet();
48 | private static bool IsFocused = false;
49 | ///
50 | /// This function is the callback used to execute a command when the a menu item is clicked.
51 | /// See the Initialize method to see how the menu item is associated to this function using
52 | /// the OleMenuCommandService service and the MenuCommand class.
53 | ///
54 | private static void FocusOnCurrentThread(object sender, EventArgs e) {
55 | try {
56 | ThreadHelper.ThrowIfNotOnUIThread();
57 | if (dte.Debugger.CurrentMode == EnvDTE.dbgDebugMode.dbgRunMode) dte.Debugger.Break();
58 | foreach (Thread thread in dte.Debugger.CurrentProgram.Threads) {
59 | try {
60 | if (!IsFocused) {
61 | if (thread.ID == dte.Debugger.CurrentThread.ID) {
62 | if (thread.IsFrozen) {
63 | thread.Thaw();
64 | }
65 | }
66 | else if (thread.IsAlive) {
67 | if (thread.IsFrozen) {
68 | IgnoredThreads.Add(thread.ID);
69 | }
70 | else {
71 | thread.Freeze();
72 | }
73 | }
74 | }
75 | else {
76 | if (thread.IsFrozen && !IgnoredThreads.Contains(thread.ID)) {
77 | thread.Thaw();
78 | }
79 | }
80 | }
81 | catch (Exception) {
82 | // ignored
83 | }
84 | }
85 | if (!IsFocused) {
86 | IsFocused = true;
87 | FocusCmd.Checked = true;
88 | SwitchCmd.Enabled = true;
89 | }
90 | else {
91 | IgnoredThreads.Clear();
92 | IsFocused = false;
93 | FocusCmd.Checked = false;
94 | SwitchCmd.Enabled = false;
95 | }
96 | }
97 | catch (Exception) {
98 | // ignored
99 | }
100 | }
101 |
102 | private static void SwitchToNextThread(object sender, EventArgs e) {
103 | var remainingAttempts = 1000;
104 | try {
105 | ThreadHelper.ThrowIfNotOnUIThread();
106 | if (dte.Debugger.CurrentMode != EnvDTE.dbgDebugMode.dbgBreakMode) return;
107 | IsFocused = true;
108 | var terminatedThreads = new HashSet();
109 | while (true) {
110 | var liveThreads = dte.Debugger.CurrentProgram.Threads.Cast().Where(t => t.IsAlive && t.Name != "[Thread Destroyed]" && !terminatedThreads.Contains(t.ID)).OrderBy(t => t.ID).ToList();
111 | // It is still to be found how to match an EnvDTE thread to a System.Threading.Thread to sort based on the ManagedThreadID, if possible and desirable at all.
112 | if (!liveThreads.Any()) return;
113 | var nextThread = liveThreads.FirstOrDefault(t => t.ID > dte.Debugger.CurrentThread.ID) ?? liveThreads.First();
114 | foreach (var thread in liveThreads.Where(thread => !thread.IsFrozen)) {
115 | try {
116 | thread.Freeze();
117 | }
118 | catch (Exception) {
119 | // ignored
120 | }
121 | }
122 | try {
123 | nextThread.Thaw();
124 | //IgnoredThreads.Remove(nextThread.ID);
125 | }
126 | catch (Exception) {
127 | if (remainingAttempts-- > 0) {
128 | terminatedThreads.Add(nextThread.ID);
129 | continue;
130 | }
131 | // ignored
132 | return;
133 | }
134 | dte.Debugger.CurrentThread = nextThread;
135 | break;
136 | }
137 | }
138 | catch (Exception) {
139 | // ignored
140 | }
141 | }
142 |
143 | private static void OnBeforeQueryStatus(object sender, EventArgs e) {
144 | if (sender is OleMenuCommand myCommand) {
145 | if (dte.Mode == EnvDTE.vsIDEMode.vsIDEModeDebug) {
146 | if (myCommand.CommandID.Guid != SwitchCmd.CommandID.Guid || dte.Debugger.CurrentMode == EnvDTE.dbgDebugMode.dbgBreakMode) {
147 | if (myCommand.CommandID.Guid != SwitchCmd.CommandID.Guid && IsFocused) {
148 | myCommand.Checked = true;
149 | }
150 | myCommand.Enabled = true;
151 | myCommand.Visible = true;
152 | }
153 | else {
154 | myCommand.Enabled = false;
155 | myCommand.Visible = false;
156 | }
157 | }
158 | else {
159 | IsFocused = false;
160 | myCommand.Checked = false;
161 | myCommand.Enabled = false;
162 | myCommand.Visible = false;
163 | }
164 | }
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/DebugSingleThreadShared/PkgCmdID.cs:
--------------------------------------------------------------------------------
1 | // PkgCmdID.cs
2 | // MUST match PkgCmdID.h
3 | using System;
4 |
5 | namespace ErwinMayerLabs.DebugSingleThread
6 | {
7 | static class PkgCmdIDList
8 | {
9 | public const uint FocusOnCurrentThreadCmd = 0x100;
10 | public const uint SwitchToNextThreadCmd = 0x101;
11 | };
12 | }
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Assets/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Assets/Icon.png
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Assets/Images_32bit.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Assets/Images_32bit.psd
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Assets/flake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Assets/flake.png
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Assets/image1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Assets/image1.png
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Assets/image2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Assets/image2.png
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/DebugSingleThread.vsct:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 |
32 |
33 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
50 |
51 |
58 |
69 |
80 |
81 |
82 |
83 |
84 |
85 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Icon.png
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Images_32bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Images_32bit.png
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Key.snk
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/License.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2011 Erwin Mayer
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/DebugSingleThreadSharedFolder/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mayerwin/vs-debug-single-thread/a3646b291e69655dcba42236b9179943378f9ef5/DebugSingleThreadSharedFolder/Screenshot.png
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2011 Erwin Mayer
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Debug Single Thread - Visual Studio Extension
2 | 
3 |
4 | This is the official repository for:
5 | https://marketplace.visualstudio.com/items?itemName=mayerwin.DebugSingleThread
6 |
7 | Initial release page here:
8 | http://erwinmayer.com/labs/visual-studio-2010-extension-debug-single-thread
9 |
10 | **Description**
11 |
12 | This Visual Studio extension adds two shortcuts and toolbar buttons to allow developers to easily focus on single threads while debugging multi-threaded applications.
13 | It dramatically reduces the need to manually go into the Threads window to freeze/thaw all threads but the one that needs to be followed, and therefore helps improve productivity.
14 |
15 | **Features**
16 | - Restrict further execution to the current thread only. Will freeze all other threads. Shortcut: `CTRL+T+T` or `snowflake` button. Click button again to thaw all other threads. Known frozen threads before the command runs (e.g. due to a breakpoint) will be remembered and not thawed. If this is not what you expect, please let me know so I can add an option to customize behavior.
17 | - Switch to the next single thread (based on ID). Will change current thread and freeze all other threads. Shortcut: `CTRL+T+J` or `Next` button.
18 |
19 | **Supported editions**
20 |
21 | Visual Studio 2015, 2017, 2019, 2022+.
22 |
23 | Visual Studio 2017 and 2019 support has been temporarily dropped due to limitations imposed by Microsoft's Visual Studio Marketplace. The last stable release (4.0.0) supporting Visual Studio 2019 can however be downloaded [here](https://github.com/mayerwin/vs-debug-single-thread/releases/tag/4.0.0).
24 |
25 | Visual Studio 2012 and 2013 support has been dropped due to new requirements imposed by Microsoft to speed up loading time with AsyncPackage. The last stable release supporting Visual Studio 2012 and 2013 can however be downloaded [here](https://github.com/mayerwin/vs-debug-single-thread/releases/tag/1.1.3_2012-2017).
26 |
27 | Visual Studio 2010 support has been dropped due to limitations imposed by Microsoft's VSIX format to support Visual Studio 2017. The last stable release supporting Visual Studio 2010 can however be downloaded [here](https://github.com/mayerwin/vs-debug-single-thread/releases/tag/1.1.3).
28 |
29 | You are welcome to contribute to this project!
30 |
--------------------------------------------------------------------------------