ソリューションファイルに十分な数のプロジェクトが含まれている場合、バイナリファイルのアセンブリはかなりの時間を要するプロセスになり、アセンブリに関するレポートは数メガバイトのサイズのシートになります。 個人的に、私はそのようなスケールで最後に似たようなラインがあります。
========== Build: 258 succeeded, 1 failed, 40 up-to-date, 1 skipped ==========
そして、戸惑うことに加えて、自然な質問:実際、何が壊れたのか? もちろん、「エラーリスト」タブはありますが、残念ながら、プロジェクトの名前は表示されません。ファイルだけで、ソースコードが大量にあるため、大規模なチームがこのソリューションに取り組んでいるという事実を考えると、メモリで判断するのは非常に困難ですファイルが特定のプロジェクトに属していること(壊れたアセンブリの原因となっているものを特定します)。 私の意見では、エラーを含むプロジェクトの名前を検索してレポートをスクロールすることは完全に推奨されていません。
上記のすべてを考慮に入れて、VS Exstensibilityが何であるかを少し理解しながら、ビジネスに喜びを組み合わせることにし、スタジオに少しの「便利さ」を提供することにしました。 「利便性」により、ワンクリックでアセンブリレポートから不要なものをすべて除外し、エラーメッセージとそれらを含むプロジェクト名のみを残すことができます。
すべてが非常にシンプルであることが判明しました。 既製のプロジェクトテンプレートから始めます。

最後に、かなり明確なクラスのセットで終わります。これにより、エディターのヒントのみを使用して、ドキュメントを実際に調べないようにすることができます。
プロジェクトを作成した後、非常に多くのコードが生成されます(言語の選択が提供されます。私の場合はC#)。 実際、興味深いのは、OnConnectメソッドとExecメソッドの2つの場所だけです。1つ目は、初期化を推測できるように、2つ目はロジックの直接の実装です。
[ツール]メニューで新しいアイテムを作成するには、OnConnectのみが必要です。 実際、私たちのために生成されたコードでは、これらすべてがすでに存在するため、コマンド自体の作成のみを修正できます。
try
{
//Add a command to the Commands collection:
Command command = commands.AddNamedCommand2(_addInInstance,
"BuildStat" ,
"Show failed build parts" ,
"Provides information about failed parts of performed solution build" ,
true ,
56,
ref contextGUIDS,
( int )vsCommandStatus.vsCommandStatusSupported + ( int )vsCommandStatus.vsCommandStatusEnabled,
( int )vsCommandStyle.vsCommandStylePictAndText,
vsCommandControlType.vsCommandControlTypeButton);
//Add a control for the command to the tools menu:
if ((command != null ) && (toolsPopup != null ))
{
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch (System.ArgumentException)
{
//If we are here, then the exception is probably because a command with that name
// already exists. If so there is no need to recreate the command and we can
// safely ignore the exception.
}
* This source code was highlighted with Source Code Highlighter .
try
{
//Add a command to the Commands collection:
Command command = commands.AddNamedCommand2(_addInInstance,
"BuildStat" ,
"Show failed build parts" ,
"Provides information about failed parts of performed solution build" ,
true ,
56,
ref contextGUIDS,
( int )vsCommandStatus.vsCommandStatusSupported + ( int )vsCommandStatus.vsCommandStatusEnabled,
( int )vsCommandStyle.vsCommandStylePictAndText,
vsCommandControlType.vsCommandControlTypeButton);
//Add a control for the command to the tools menu:
if ((command != null ) && (toolsPopup != null ))
{
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch (System.ArgumentException)
{
//If we are here, then the exception is probably because a command with that name
// already exists. If so there is no need to recreate the command and we can
// safely ignore the exception.
}
* This source code was highlighted with Source Code Highlighter .
try
{
//Add a command to the Commands collection:
Command command = commands.AddNamedCommand2(_addInInstance,
"BuildStat" ,
"Show failed build parts" ,
"Provides information about failed parts of performed solution build" ,
true ,
56,
ref contextGUIDS,
( int )vsCommandStatus.vsCommandStatusSupported + ( int )vsCommandStatus.vsCommandStatusEnabled,
( int )vsCommandStyle.vsCommandStylePictAndText,
vsCommandControlType.vsCommandControlTypeButton);
//Add a control for the command to the tools menu:
if ((command != null ) && (toolsPopup != null ))
{
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch (System.ArgumentException)
{
//If we are here, then the exception is probably because a command with that name
// already exists. If so there is no need to recreate the command and we can
// safely ignore the exception.
}
* This source code was highlighted with Source Code Highlighter .
その結果、以下が得られます。

アセンブリレポートフィルタリングの実装は引き続き行われます。 これを行うには、「出力/ビルド」ウィンドウからレポート自体を取得し、必要なものだけを残して、「出力」ウィンドウに新しいパネルを作成し、作業結果を入力する必要があります。 したがって、Execメソッドは次の形式を取ります。
public void Exec( string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false ;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if (commandName == "BuildStat.Connect.BuildStat" )
{
handled = true ;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build" )
{
//
TextDocument textDocument = pane.TextDocument;
textDocument.Selection.StartOfDocument( false );
textDocument.Selection.EndOfDocument( true );
String buildLog = textDocument.Selection.Text;
if (buildLog.Length > 0)
{
string parsedLog = Parse(buildLog);
if (parsedLog.Length > 0)
Output(parsedLog);
}
break ;
}
}
return ;
}
}
}
* This source code was highlighted with Source Code Highlighter .
public void Exec( string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false ;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if (commandName == "BuildStat.Connect.BuildStat" )
{
handled = true ;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build" )
{
//
TextDocument textDocument = pane.TextDocument;
textDocument.Selection.StartOfDocument( false );
textDocument.Selection.EndOfDocument( true );
String buildLog = textDocument.Selection.Text;
if (buildLog.Length > 0)
{
string parsedLog = Parse(buildLog);
if (parsedLog.Length > 0)
Output(parsedLog);
}
break ;
}
}
return ;
}
}
}
* This source code was highlighted with Source Code Highlighter .
public void Exec( string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false ;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if (commandName == "BuildStat.Connect.BuildStat" )
{
handled = true ;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build" )
{
//
TextDocument textDocument = pane.TextDocument;
textDocument.Selection.StartOfDocument( false );
textDocument.Selection.EndOfDocument( true );
String buildLog = textDocument.Selection.Text;
if (buildLog.Length > 0)
{
string parsedLog = Parse(buildLog);
if (parsedLog.Length > 0)
Output(parsedLog);
}
break ;
}
}
return ;
}
}
}
* This source code was highlighted with Source Code Highlighter .
少しの文字列処理:
private string Parse( string buildLog)
{
String parseResult = "" ;
StringReader logReader = new StringReader (buildLog);
Regex failedProjects = new Regex( "[1-9][0-9]* error\\(s\\), [0-9]+ warning\\(s\\)" );
for ( string line = logReader.ReadLine(); line != null ; line = logReader.ReadLine())
{
if (failedProjects.IsMatch(line))
{
parseResult += line;
parseResult += "\r\n" ;
}
if ((line.IndexOf( ": error" ) != -1) || (line.IndexOf( ": fatal error" ) != -1))
{
parseResult += line;
parseResult += "\r\n" ;
}
}
return parseResult;
}
* This source code was highlighted with Source Code Highlighter .
private string Parse( string buildLog)
{
String parseResult = "" ;
StringReader logReader = new StringReader (buildLog);
Regex failedProjects = new Regex( "[1-9][0-9]* error\\(s\\), [0-9]+ warning\\(s\\)" );
for ( string line = logReader.ReadLine(); line != null ; line = logReader.ReadLine())
{
if (failedProjects.IsMatch(line))
{
parseResult += line;
parseResult += "\r\n" ;
}
if ((line.IndexOf( ": error" ) != -1) || (line.IndexOf( ": fatal error" ) != -1))
{
parseResult += line;
parseResult += "\r\n" ;
}
}
return parseResult;
}
* This source code was highlighted with Source Code Highlighter .
private string Parse( string buildLog)
{
String parseResult = "" ;
StringReader logReader = new StringReader (buildLog);
Regex failedProjects = new Regex( "[1-9][0-9]* error\\(s\\), [0-9]+ warning\\(s\\)" );
for ( string line = logReader.ReadLine(); line != null ; line = logReader.ReadLine())
{
if (failedProjects.IsMatch(line))
{
parseResult += line;
parseResult += "\r\n" ;
}
if ((line.IndexOf( ": error" ) != -1) || (line.IndexOf( ": fatal error" ) != -1))
{
parseResult += line;
parseResult += "\r\n" ;
}
}
return parseResult;
}
* This source code was highlighted with Source Code Highlighter .
そして、画面出力自体:
private void Output( string outputString)
{
OutputWindowPane myPane = null ;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build [failed]" )
{
myPane = pane;
break ;
}
}
if (myPane == null )
myPane = _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes.Add( "Build [failed]" );
myPane.Clear();
myPane.OutputString(outputString);
myPane.Activate();
}
* This source code was highlighted with Source Code Highlighter .
private void Output( string outputString)
{
OutputWindowPane myPane = null ;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build [failed]" )
{
myPane = pane;
break ;
}
}
if (myPane == null )
myPane = _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes.Add( "Build [failed]" );
myPane.Clear();
myPane.OutputString(outputString);
myPane.Activate();
}
* This source code was highlighted with Source Code Highlighter .
private void Output( string outputString)
{
OutputWindowPane myPane = null ;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build [failed]" )
{
myPane = pane;
break ;
}
}
if (myPane == null )
myPane = _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes.Add( "Build [failed]" );
myPane.Clear();
myPane.OutputString(outputString);
myPane.Activate();
}
* This source code was highlighted with Source Code Highlighter .
結果は次のとおりです。

モジュールをインストールするには、プロジェクト内にある.AddInファイルを「My Documents \ Visual Studio <バージョン> \ Addins」にコピーする必要があります。パスなどの必要なフィールドを修正することを忘れないでください。
PS自転車が発明されたという感覚はありますが、わずか30分間の時間や受け取った喜びのわずかな部分など、さまざまな要因の組み合わせがすべてを補います。