Skip to content

Commit

Permalink
Merge pull request #58 from KrzysztofBuchacz/vs2022
Browse files Browse the repository at this point in the history
Update for Visual Studio 2022
  • Loading branch information
KrzysztofBuchacz authored Dec 28, 2021
2 parents 0d2fc56 + c2cd191 commit 947d83f
Show file tree
Hide file tree
Showing 26 changed files with 291 additions and 406 deletions.
9 changes: 0 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,6 @@ publish/
*.pubxml
*.publishproj

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# If using the old MSBuild-Integrated Package Restore, uncomment this:
#!**/packages/repositories.config

# Windows Azure Build Output
csx/
*.build.csdef
Expand Down
4 changes: 2 additions & 2 deletions ParallelBuildsMonitor.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.168
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelBuildsMonitor", "Plugin\ParallelBuildsMonitor.csproj", "{D045634D-A98B-4D34-9B92-2C1F2D45CB8F}"
EndProject
Expand Down
18 changes: 9 additions & 9 deletions Plugin/DataModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ public class DataModel : IDisposable

#region Members

private Dictionary<string, Tuple<uint, long>> currentBuilds = new Dictionary<string, Tuple<uint, long>>(); //<c>string</c> is ProjectUniqueName, <c>uint</c> is project build order number, <c>long</c> is project Start time, relative, counted since <c>DataModel.StartTime</c> in <c>DateTime.Ticks</c> units.
private List<BuildInfo> finishedBuilds = new List<BuildInfo>();
private readonly Dictionary<string, Tuple<uint, long>> currentBuilds = new Dictionary<string, Tuple<uint, long>>(); //<c>string</c> is ProjectUniqueName, <c>uint</c> is project build order number, <c>long</c> is project Start time, relative, counted since <c>DataModel.StartTime</c> in <c>DateTime.Ticks</c> units.
private readonly List<BuildInfo> finishedBuilds = new List<BuildInfo>();
private Dictionary<string, List<string>> projectDependenies = new Dictionary<string, List<string>>(); //<c>string</c> is ProjectUniqueName, <c>List<string></c> is list of projects that <c>Key</c> project depends on
private List<BuildInfo> criticalPath = new List<BuildInfo>();
private readonly List<BuildInfo> criticalPath = new List<BuildInfo>();

private List<Tuple<long, float>> cpuUsage = new List<Tuple<long, float>>();
private List<Tuple<long, float>> hddUsage = new List<Tuple<long, float>>();
private readonly List<Tuple<long, float>> cpuUsage = new List<Tuple<long, float>>();
private readonly List<Tuple<long, float>> hddUsage = new List<Tuple<long, float>>();

private PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
private PerformanceCounter hddCounter = new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
private static readonly double performanceTimerInterval = 1000; // 1000 means collect data every 1s.
private System.Timers.Timer performanceTimer = new System.Timers.Timer(performanceTimerInterval);
private readonly PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
private readonly PerformanceCounter hddCounter = new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
private readonly static double performanceTimerInterval = 1000; // 1000 means collect data every 1s.
private readonly System.Timers.Timer performanceTimer = new System.Timers.Timer(performanceTimerInterval);

static uint projectBuildOrderNumber = 0;

Expand Down
1 change: 0 additions & 1 deletion Plugin/DetectSsd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ private static extern bool DeviceIoControl(

// From: https://referencesource.microsoft.com/#system/compmod/microsoft/win32/SafeNativeMethods.cs
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true, BestFitMapping = true)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2101:SpecifyMarshalingForPInvokeStringArguments")] // This warning doesn't exist any longer, however there is different one, and some troubles to disable it.
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
static extern uint FormatMessage(
uint dwFlags,
Expand Down
63 changes: 63 additions & 0 deletions Plugin/Events/BuildEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

namespace ParallelBuildsMonitor.Events
{
internal class BuildEvents : IVsUpdateSolutionEvents2
{
private uint dwLastAction;

public int UpdateSolution_StartUpdate(ref int pfCancelUpdate)
{
return VSConstants.S_OK;
}

public int UpdateSolution_Cancel()
{
return VSConstants.S_OK;
}

public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy)
{
return VSConstants.S_OK;
}

public int UpdateSolution_Begin(ref int pfCancelUpdate)
{
dwLastAction = 0;
PBMCommand.BuildEvents_OnBuildBegin();
return VSConstants.S_OK;
}

public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand)
{
// Find critical path only for Build action not for Clean or any other action
bool findAndSetCriticalPath = (dwLastAction & (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD) != 0;
PBMCommand.BuildEvents_OnBuildDone(findAndSetCriticalPath);
return VSConstants.S_OK;
}

private string ProjectUniqueName(IVsHierarchy pHierProj)
{
ThreadHelper.ThrowIfNotOnUIThread();
pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out object project);
return (project as EnvDTE.Project).UniqueName;
}

public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel)
{
ThreadHelper.ThrowIfNotOnUIThread();
PBMCommand.BuildEvents_OnBuildProjConfigBegin(ProjectUniqueName(pHierProj));
dwLastAction = dwAction;
return VSConstants.S_OK;
}

public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel)
{
ThreadHelper.ThrowIfNotOnUIThread();
PBMCommand.BuildEvents_OnBuildProjConfigDone(ProjectUniqueName(pHierProj), fSuccess != 0);
return VSConstants.S_OK;
}
}
}
60 changes: 60 additions & 0 deletions Plugin/Events/SolutionEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;


namespace ParallelBuildsMonitor.Events
{
internal class SolutionEvents : IVsSolutionEvents
{
public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
{
return VSConstants.S_OK;
}

public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
{
return VSConstants.S_OK;
}

public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
{
return VSConstants.S_OK;
}

public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
{
return VSConstants.S_OK;
}

public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
{
return VSConstants.S_OK;
}

public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnBeforeCloseSolution(object pUnkReserved)
{
return VSConstants.S_OK;
}

public int OnAfterCloseSolution(object pUnkReserved)
{
PBMCommand.AfterSolutionClosing();
return VSConstants.S_OK;
}
}
}
33 changes: 15 additions & 18 deletions Plugin/GraphControl.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using EnvDTE;
using EnvDTE80;
using System.Collections.ObjectModel;
using System.Diagnostics;

Expand Down Expand Up @@ -46,8 +41,8 @@ private class Spacings

#region Members

private static readonly double refreshTimerInterval = 1000; // 1000 means collect data every 1s.
private System.Timers.Timer refreshTimer = new System.Timers.Timer(refreshTimerInterval);
private readonly static double refreshTimerInterval = 1000; // 1000 means collect data every 1s.
private readonly System.Timers.Timer refreshTimer = new System.Timers.Timer(refreshTimerInterval);
private long nowTickForTest = 0; // This value is used only when greater from 0 and only for testing. Rationale: GraphControl refresh itself, but for test constant data is required.

#endregion Members
Expand Down Expand Up @@ -98,7 +93,7 @@ public GraphControl()
{
Instance = this;
fontFace = new Typeface(FontFamily.Source);
rowHeight = (new FormattedText("A0", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush)).Height + penThickness;
rowHeight = (new FormattedText("A0", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip)).Height + penThickness;
OnForegroundChanged();
refreshTimer.Elapsed += new ElapsedEventHandler(RefreshTimerEventTick); // Are we sure there is only one instance of GraphControl? If not operator += will multiply calls...

Expand Down Expand Up @@ -239,7 +234,7 @@ void DrawGraph(string title, DrawingContext drawingContext, ReadOnlyCollection<T
if (sumTicks > 0)
{
long average = (long)(sumValues / 2 / sumTicks);
FormattedText avg = new FormattedText(" (Avg. " + average.ToString() + "%)", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText avg = new FormattedText(" (Avg. " + average.ToString() + "%)", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
title += avg.Text;
}

Expand All @@ -249,7 +244,7 @@ void DrawGraph(string title, DrawingContext drawingContext, ReadOnlyCollection<T

private void DrawText(DrawingContext drawingContext, string caption, int rowNbr, double xPos, Brush textColor)
{
FormattedText captionFT = new FormattedText(caption, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, textColor);
FormattedText captionFT = new FormattedText(caption, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, textColor, VisualTreeHelper.GetDpi(this).PixelsPerDip);
drawingContext.DrawText(captionFT, new Point(xPos, rowNbr * rowHeight));
}

Expand Down Expand Up @@ -287,7 +282,7 @@ private void DrawMachineInfo(DrawingContext drawingContext, int rowNbr)
{
string headerText = DataModel.GetSolutionNameWithMachineInfo(" | ", false /*WithBuildStartedStr*/);

FormattedText itext = new FormattedText(headerText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText itext = new FormattedText(headerText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
// Cut text when it is too long for window - Set a maximum width and height. If the text overflows those values, an ellipsis "..." appears.
itext.MaxTextWidth = RenderSize.Width - Spacings.lOrder - Spacings.rGanttC;
itext.MaxTextHeight = rowHeight;
Expand Down Expand Up @@ -329,7 +324,7 @@ private void DrawBar(DrawingContext drawingContext, int rowNbr, long startTime,
}

string time = Utils.SecondsToString(endTime - startTime);
FormattedText itime = new FormattedText(time, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, whiteBrush);
FormattedText itime = new FormattedText(time, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, whiteBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
double timeLen = itime.Width;
if (r.Width > timeLen)
{
Expand Down Expand Up @@ -374,7 +369,7 @@ protected override void OnRender(DrawingContext drawingContext)

if (IsEmptyBuilds())
{ // Case when no single build was started yet - display some info to ensure user that everything is OK
FormattedText captionFT = new FormattedText(emptyGanttMsg, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText captionFT = new FormattedText(emptyGanttMsg, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
drawingContext.DrawText(captionFT, new Point(50.0, rowNbrNoProjectsFiller / 2 * rowHeight));

return;
Expand Down Expand Up @@ -402,7 +397,7 @@ protected override void OnRender(DrawingContext drawingContext)
double projectNameMaxLen = 10;
for (ii = 0; ii < DataModel.FinishedBuilds.Count; ii++)
{
FormattedText iname = new FormattedText(DataModel.FinishedBuilds[ii].ProjectName, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText iname = new FormattedText(DataModel.FinishedBuilds[ii].ProjectName, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
double ll = iname.Width;
t = DataModel.FinishedBuilds[ii].end;
atLeastOneError = atLeastOneError || !DataModel.FinishedBuilds[ii].success;
Expand All @@ -417,7 +412,7 @@ protected override void OnRender(DrawingContext drawingContext)
}
foreach (KeyValuePair<string, Tuple<uint, long>> item in DataModel.CurrentBuilds)
{
FormattedText iname = new FormattedText(DataModel.GetHumanReadableProjectName(item.Key), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText iname = new FormattedText(DataModel.GetHumanReadableProjectName(item.Key), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
double ll = iname.Width;
if (ll > projectNameMaxLen)
projectNameMaxLen = ll;
Expand All @@ -435,14 +430,14 @@ protected override void OnRender(DrawingContext drawingContext)
string pattern = "> ";
int len = maxBuildOrderNbr.ToString().Length + pattern.Length;
pattern = pattern.PadLeft(len, '8'); // let's assume that 8 is the widest char
FormattedText bn = new FormattedText(pattern, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText bn = new FormattedText(pattern, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);

spacings.lProjName = Spacings.lOrder + bn.Width + 3; // let's add 3 pix just in case 8 is not the widest
spacings.lGanttC = spacings.lProjName + projectNameMaxLen + penThickness + 3; // let's add 3 pix just in case
}

// check if usage text is longer than the longest project name, and yes, values greater than 1000% are possible
double usageTextLen = new FormattedText("HDD Usage (Avg. 1000%)", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush).Width;
double usageTextLen = new FormattedText("HDD Usage (Avg. 1000%)", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip).Width;
spacings.lGanttC = Math.Max(spacings.lGanttC, Spacings.lOrder + usageTextLen + penThickness);

int rowNbr = 0; //first row has number 0
Expand Down Expand Up @@ -496,7 +491,7 @@ protected override void OnRender(DrawingContext drawingContext)

DateTime dt = new DateTime(maxTick);
string s = Utils.SecondsToString(dt.Ticks);
FormattedText maxTime = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
FormattedText maxTime = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
double m = maxTime.Width;
drawingContext.DrawText(maxTime, new Point(RenderSize.Width - m - Spacings.rGanttC, rowNbr * rowHeight));

Expand All @@ -522,7 +517,9 @@ protected override void OnRender(DrawingContext drawingContext)

private void RefreshTimerEventTick(object sender, ElapsedEventArgs e)
{
#pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs
GraphControl.Instance.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background,
#pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs
new System.Action(() =>
{
GraphControl.Instance.InvalidateVisual();
Expand Down
Loading

0 comments on commit 947d83f

Please sign in to comment.