logic: Added plugin Logging

Added plugin file logging and exception handling.
Also fixed some reported bugs from the last release version.
Updated documentation.
This commit is contained in:
wrongway88
2016-10-26 17:58:20 +02:00
parent e78162fa43
commit 38d0cb36aa
28 changed files with 1575 additions and 458 deletions
@@ -1,6 +1,11 @@
-Check latest plugin version is installed
-Start VS and load a C/C++ solution (best mixed with multiple projects)
-Check all projects are loaded in Solution Explorer
-Check Plugin Logging and Obfuscation is off
-VS Menu Bar -> Tools -> Options -> Coati -> Logging & Obfuscation is off
-Delete log file and dictionary for current VS session if present
-delete log file for current session at ..AppData/Local/Coati Software/Plugin/VS if present
-delete dictionary file for current session at ..AppData/Local/Coati Software/Plugin/VS if present
-Create CDB from solution
-Check all C/C++ projects listed in CDB dialogue
-Check eventual non-C/C++ projects are not listed
@@ -29,25 +34,47 @@
-Check finished CDB
-check at correct location with correct name
-check CDB file is non-empty (at least estimate whether number of lines in CDB coincides with VS solution)
-Check no new Log file or Dictionary file was created
-Check ..AppData/Local/Coati Software/Plugin/VS for no new log created
-Check ..AppData/Local/Coati Software/Plugin/VS for no new dictionary created
-Turn on Logging
-VS Menu Bar -> Tools -> Options -> Coati -> Logging ON & Obfuscation OFF
-Enable VS Output Window
-VS Menu Bar -> View -> Output
-In Output Window, show Coati log (Show Output from: Coati Log)
-Create CDB from solution again
-Check location and name is the same as last time
-Check dialogue asking whether to overwrite old file or not
-Click no
-Check number appended to file name
-Create CDB with the new name
-Check VS Output Window displays messages during creation
-Check project- and file names and directories are in clear text
-Check finished CDB
-check at correct location with correct name
-check CDB file is non-empty (at least estimate whether number of lines in CDB coincides with VS solution)
-Unload a project in the Solution Explorer
-Check new Log file but no Dictionary file was created
-Check ..AppData/Local/Coati Software/Plugin/VS for new log created
-Check ..AppData/Local/Coati Software/Plugin/VS for no new dictionary created
-Turn on Obfuscation
-VS Menu Bar -> Tools -> Options -> Coati -> Logging ON & Obfuscation ON
-Create CDB from solution again
-Check unloaded project is not in the listed projects in the dialogue
-Check location and name is the same as first time
-Check dialogue asking whether to overwrite old file or not
-Click yes
-Click Create
-Check VS Output Window displays messages during creation
-Check project- and file names and directories are obfuscated (a0, b0, c0,...)
-Check finished CDB
-check at correct location with correct name
-check CDB file is smaller now (reduced size has to make sense considering the missing project)
-Check new Log entries and Dictionary file was created
-Check ..AppData/Local/Coati Software/Plugin/VS for no new log file
-Check the log file created in this session at ..AppData/Local/Coati Software/Plugin/VS for new entries
-Check new entries are using obfuscated names
-Check ..AppData/Local/Coati Software/Plugin/VS for new dictionary created
-Create CDB from solution again
-Check location and name is the same as first time
-Check dialogue asking whether to overwrite old file or not
+6 -1
View File
@@ -11,4 +11,9 @@ These Edge Cases should be considered in a dedicated Test Solution for the Plugi
-at least two levels deep
-Include Paths
-add at least one include path to Project->Properties->Configuration Properties->VC++ Directories->Include Directories
-add at least one include path to Project->Properties->Configuration Properties->VC++ Directories->Include Directories
-Solution Structure
-have a solution with no projects directly under the solution
-so: Solution/Folder/Project
-no: Solution/Project
Binary file not shown.
@@ -129,6 +129,13 @@
</COMReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Logging\FileLogger.cs" />
<Compile Include="Logging\ILogger.cs" />
<Compile Include="Logging\Logging.cs" />
<Compile Include="Logging\LogManager.cs" />
<Compile Include="Logging\LogMessage.cs" />
<Compile Include="Logging\Obfuscation\NameObfuscator.cs" />
<Compile Include="Logging\VSOutputLogger.cs" />
<Compile Include="Utility\FileUtility.cs" />
<Compile Include="Guids.cs" />
<Compile Include="NetworkProtocolUtility.cs" />
@@ -194,7 +201,6 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="ClassDiagram1.cd" />
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
@@ -217,6 +223,7 @@
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
</ItemGroup>
<ItemGroup />
<PropertyGroup>
<UseCodebase>true</UseCodebase>
</PropertyGroup>
@@ -16,10 +16,14 @@ namespace CoatiSoftware.CoatiPlugin
{
private uint _serverPort = 6666;
private uint _clientPort = 6667;
private bool _logging = false;
private bool _obfuscateLogging = false;
public delegate void Callback();
public static Callback _serverPortChangeCallback = null;
public static Callback _clientPortChangeCallback = null;
public static Callback _loggingToggled = null;
public static Callback _obfuscationToggled = null;
[Category("Coati")]
[DisplayName("VS Port")]
@@ -53,6 +57,38 @@ namespace CoatiSoftware.CoatiPlugin
}
}
[Category("Coati")]
[DisplayName("File Logging")]
[Description("Enables or disables file logging for the plugin")]
public bool LoggingEnabled
{
get { return _logging; }
set
{
_logging = value;
if(_loggingToggled != null)
{
_loggingToggled();
}
}
}
[Category("Coati")]
[DisplayName("Log Obfuscation")]
[Description("Names will be obfuscated in log files. Note that already logged data will not be obfuscated retroactively. A dictionary file will be created that you can use to make sense of obfuscated logs. Keep this dictionary to yourself!")]
public bool ObfuscateLogging
{
get { return _obfuscateLogging; }
set
{
_obfuscateLogging = value;
if (_obfuscationToggled != null)
{
_obfuscationToggled();
}
}
}
public OptionPageGrid()
{
}
@@ -91,6 +127,24 @@ namespace CoatiSoftware.CoatiPlugin
}
}
public bool LoggingEnabled
{
get
{
OptionPageGrid page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
return page.LoggingEnabled;
}
}
public bool LogObfuscationEnabled
{
get
{
OptionPageGrid page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
return page.ObfuscateLogging;
}
}
System.Threading.Thread _serverThread = null;
public CoatiPluginPackage()
@@ -100,12 +154,15 @@ namespace CoatiSoftware.CoatiPlugin
{
base.Initialize();
InitLogging();
InitNetwork();
Utility.FileUtility._errorCallback = new Utility.FileUtility.ErrorCallback(OnFileUtilityError);
OptionPageGrid._serverPortChangeCallback = new OptionPageGrid.Callback(OnServerPortChanged);
OptionPageGrid._clientPortChangeCallback = new OptionPageGrid.Callback(OnClientPortChanged);
OptionPageGrid._loggingToggled = new OptionPageGrid.Callback(OnLoggingToggled);
OptionPageGrid._obfuscationToggled = new OptionPageGrid.Callback(OnObfuscationToggled);
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
@@ -133,10 +190,14 @@ namespace CoatiSoftware.CoatiPlugin
_solutionEvents.Opened += OnSolutionOpened;
_solutionEvents.AfterClosing += OnSolutionClosed;
Logging.Logging.LogInfo("Initialization done");
}
void OnSolutionOpened()
{
Logging.Logging.LogInfo("A solution was loaded, checking languages");
try
{
DTE dte = (DTE)GetService(typeof(DTE));
@@ -148,25 +209,34 @@ namespace CoatiSoftware.CoatiPlugin
if (language == CodeModelLanguageConstants.vsCMLanguageVC
|| language == CodeModelLanguageConstants.vsCMLanguageMC)
{
Logging.Logging.LogInfo("C/C++ project was detected");
enable = true;
}
}
if (enable)
{
Logging.Logging.LogInfo("Enabling plugin UI");
_menuItemSetActiveToken.Enabled = true;
_menuItemCreateProject.Enabled = true;
_menuItemCreateCDB.Enabled = true;
}
else
{
Logging.Logging.LogInfo("No C/C++ project was detected");
}
}
catch(Exception e)
{
DisplayMessage("Error", e.Message);
Logging.Logging.LogError(e.Message);
}
}
void OnSolutionClosed()
{
Logging.Logging.LogInfo("Solution closed, disabling plugin UI");
_menuItemSetActiveToken.Enabled = false;
_menuItemCreateProject.Enabled = false;
_menuItemCreateCDB.Enabled = false;
@@ -174,6 +244,8 @@ namespace CoatiSoftware.CoatiPlugin
private void InitNetwork()
{
Logging.Logging.LogInfo("Initializing Network with Server Port " + ServerPort.ToString() + " and Client Port " + ClientPort.ToString());
Utility.AsynchronousSocketListener._port = ServerPort;
Utility.AsynchronousSocketListener server = new Utility.AsynchronousSocketListener();
Utility.AsynchronousSocketListener._onReadCallback = new Utility.AsynchronousSocketListener.OnReadCallback(OnNetworkReadCallback);
@@ -185,6 +257,22 @@ namespace CoatiSoftware.CoatiPlugin
Utility.AsynchronousClient._onErrorCallback = new Utility.AsynchronousSocketListener.OnReadCallback(OnNetworkErrorCallback);
}
private void InitLogging()
{
DTE dte = (DTE)GetService(typeof(DTE));
Logging.FileLogger fileLogger = new Logging.FileLogger();
Logging.VSOutputLogger vsLogger = new Logging.VSOutputLogger(dte);
Logging.LogManager.GetInstance().Loggers.Add(fileLogger);
Logging.LogManager.GetInstance().Loggers.Add(vsLogger);
Logging.LogManager.GetInstance().LoggingEnabled = LoggingEnabled;
Logging.Obfuscation.NameObfuscator.Enabled(LogObfuscationEnabled);
Logging.Logging.LogInfo("Logging initialized");
}
private void OnCreateProject(List<EnvDTE.Project> projects, string configurationName, string platformName, string targetDir, string fileName, string cStandard)
{
Wizard.WindowCreateCDB createCDB = new Wizard.WindowCreateCDB();
@@ -195,19 +283,56 @@ namespace CoatiSoftware.CoatiPlugin
createCDB.FileName = fileName;
createCDB.CStandard = cStandard;
createCDB.CallbackOnFinishedCreatingCDB = WriteCDBToFile;
createCDB.CallbackOnFinishedCreatingCDB = HandleFinishedCDB;
createCDB.StartWorking();
createCDB.ShowDialog();
}
private void HandleFinishedCDB(Wizard.WindowCreateCDB.CreationResult creationResult)
{
if(creationResult._cdb != null && creationResult._cdbDirectory.Length > 0 && creationResult._cdbName.Length > 0)
{
WriteCDBToFile(creationResult._cdb, creationResult._cdbDirectory, creationResult._cdbName);
//string message = NetworkProtocolUtility.createCreateProjectMessage(creationResult._cdbDirectory + "\\" + creationResult._cdbName, creationResult._headerDirectories);
//Utility.AsynchronousClient.Send(message);
}
else
{
Logging.Logging.LogError("Invalid data received");
}
}
private void WriteCDBToFile(SolutionParser.CompilationDatabase cdb, string directory, string fileName)
{
string content = cdb.SerializeJSON();
File.WriteAllText(directory + "\\" + fileName + ".json", content);
try
{
string content = cdb.SerializeJSON();
File.WriteAllText(directory + "\\" + fileName + ".json", content);
}
catch(Exception e)
{
string foo = "Error";
string bar = "Failed to write CDB '" + fileName + "' to directory \"" + directory + "\"\n";
bar += "See log for details.";
Wizard.WindowMessage wm = new Wizard.WindowMessage();
wm.Title = foo;
wm.Message = bar;
wm.RefreshWindow();
wm.ShowDialog();
bar = "Failed to write CDB '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName) + "' to directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(directory) + "\"\n";
Logging.Logging.LogError(bar);
Logging.Logging.LogError("Exception: " + e.Message);
return;
}
string title = "CDB finished";
string message = "The CDB " + fileName + " was created at directory \"" + directory + "\"\n";
string message = "The CDB '" + fileName + "' was created at directory \"" + directory + "\"\n";
message += "You can now use it in Coati.";
Wizard.WindowMessage windowMessage = new Wizard.WindowMessage();
@@ -215,6 +340,9 @@ namespace CoatiSoftware.CoatiPlugin
windowMessage.Message = message;
windowMessage.RefreshWindow();
windowMessage.ShowDialog();
message = "The CDB '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName) + "' was created at directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(directory) + "\"\n";
Logging.Logging.LogInfo(message);
}
private void MenuItemCallback(object sender, EventArgs e)
@@ -301,16 +429,20 @@ namespace CoatiSoftware.CoatiPlugin
private void OnNetworkErrorCallback(string message)
{
Logging.Logging.LogError("Network Error: " + message.ToString());
DisplayMessage("Coati Network Error", message);
}
private void OnFileUtilityError(string message)
{
Logging.Logging.LogError("File Error: " + message.ToString());
DisplayMessage("Coati File Error", message);
}
private void OnServerPortChanged()
{
Logging.Logging.LogInfo("Changing Server Port to " + ServerPort.ToString());
Utility.AsynchronousSocketListener._port = ServerPort;
_serverThread.Abort();
@@ -321,9 +453,35 @@ namespace CoatiSoftware.CoatiPlugin
private void OnClientPortChanged()
{
Logging.Logging.LogInfo("Changing Client Port to " + ClientPort.ToString());
Utility.AsynchronousClient._port = ClientPort;
}
private void OnLoggingToggled()
{
Logging.LogManager.GetInstance().LoggingEnabled = LoggingEnabled;
if(LoggingEnabled)
{
Logging.Logging.LogInfo("Logging enabled");
}
}
private void OnObfuscationToggled()
{
Logging.Obfuscation.NameObfuscator.Enabled(LogObfuscationEnabled);
if(LogObfuscationEnabled)
{
Logging.Logging.LogInfo("Log Obfuscation enabled");
}
else
{
Logging.Logging.LogInfo("Log Obfuscation disabled");
}
}
private void DisplayMessage(string title, string message)
{
IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
@@ -345,6 +503,8 @@ namespace CoatiSoftware.CoatiPlugin
private void CreateCompilationDatabase(DTE dte)
{
Logging.Logging.LogInfo("Preparing CDB dialog");
Wizard.ProjectSetupWindow window = new Wizard.ProjectSetupWindow();
Utility.SolutionUtility.SolutionStructure projectStructure = Utility.SolutionUtility.GetSolutionVCProjects(dte);
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
namespace CoatiSoftware.CoatiPlugin.Logging
{
class FileLogger : ILogger
{
private static string _directory = "";
private static string _fileNamePrefix = "Log_CoatiPlugin_";
private static string _fileNameSufix = ".txt";
private string _fileName = "";
private Queue<string> _messageBacklog = new Queue<string>(); // stores messages if the log file was in use at original logging time
public FileLogger()
{
DateTime time = DateTime.Now;
string dateString = "";
dateString += time.Year.ToString() + "-" + time.Month.ToString() + "-" + time.Day.ToString() + "_";
dateString += time.Hour.ToString() + "-" + time.Minute.ToString() + "-" + time.Second.ToString();
_fileName = _fileNamePrefix + dateString + _fileNameSufix;
_directory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
_directory += "\\Coati Software\\Plugins\\VS\\";
if(System.IO.Directory.Exists(_directory) == false)
{
System.IO.Directory.CreateDirectory(_directory);
}
}
public void LogMessage(LogMessage message)
{
System.IO.StreamWriter writer = null;
try
{
writer = System.IO.File.AppendText(_directory + _fileName);
// write backlog to file first
while(_messageBacklog.Count > 0)
{
string bm = _messageBacklog.Dequeue();
writer.WriteLine(bm);
}
writer.WriteLine(message.ToString());
writer.Close();
}
catch(Exception e)
{
// well...file is still in use
_messageBacklog.Enqueue(message.ToString());
}
finally
{
if(writer != null)
{
writer.Close();
}
}
}
}
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CoatiSoftware.CoatiPlugin.Logging
{
public interface ILogger
{
void LogMessage(LogMessage message);
}
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CoatiSoftware.CoatiPlugin.Logging
{
public class LogManager
{
private static LogManager _instance = null;
private List<ILogger> _loggers = new List<ILogger>();
private bool _loggingEnabled = false;
public List<ILogger> Loggers
{
get { return _loggers; }
set { _loggers = value; }
}
public bool LoggingEnabled
{
get { return _loggingEnabled; }
set { _loggingEnabled = value; }
}
private LogManager()
{
}
public static LogManager GetInstance()
{
if(_instance == null)
{
_instance = new LogManager();
}
return _instance;
}
public void LogInfo(string message, string sourceFile, string callingFunction, int lineNumber)
{
LogMessage logMessage = new LogMessage();
logMessage.Message = message;
logMessage.MessageType = LogMessage.LogMessageType.INFO;
logMessage.Time = DateTime.Now;
logMessage.SourceFile = sourceFile;
logMessage.CallingFunction = callingFunction;
logMessage.LineNumber = lineNumber;
Log(logMessage);
}
public void LogWarning(string message, string sourceFile, string callingFunction, int lineNumber)
{
LogMessage logMessage = new LogMessage();
logMessage.Message = message;
logMessage.MessageType = LogMessage.LogMessageType.WARNING;
logMessage.Time = DateTime.Now;
logMessage.SourceFile = sourceFile;
logMessage.CallingFunction = callingFunction;
logMessage.LineNumber = lineNumber;
Log(logMessage);
}
public void LogError(string message, string sourceFile, string callingFunction, int lineNumber)
{
LogMessage logMessage = new LogMessage();
logMessage.Message = message;
logMessage.MessageType = LogMessage.LogMessageType.ERROR;
logMessage.Time = DateTime.Now;
logMessage.SourceFile = sourceFile;
logMessage.CallingFunction = callingFunction;
logMessage.LineNumber = lineNumber;
Log(logMessage);
}
private void Log(LogMessage message)
{
if(_loggingEnabled == true)
{
foreach (ILogger logger in _loggers)
{
logger.LogMessage(message);
}
}
}
}
}
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CoatiSoftware.CoatiPlugin.Logging
{
public class LogMessage
{
public enum LogMessageType
{
UNKNOWN = 0,
INFO,
WARNING,
ERROR
}
private string _message = "";
private DateTime _time = new DateTime();
private LogMessageType _messageType = LogMessageType.UNKNOWN;
private string _sourceFile = "";
private string _callingFunction = "";
private int _lineNumber = -1;
public string Message
{
get { return _message; }
set { _message = value; }
}
public DateTime Time
{
get { return _time; }
set { _time = value; }
}
public LogMessageType MessageType
{
get { return _messageType; }
set { _messageType = value; }
}
public string SourceFile
{
get { return _sourceFile; }
set { _sourceFile = value; }
}
public string CallingFunction
{
get { return _callingFunction; }
set { _callingFunction = value; }
}
public int LineNumber
{
get { return _lineNumber; }
set { _lineNumber = value; }
}
public override string ToString()
{
string result = "";
result += _time.Hour.ToString() + ":" + _time.Minute.ToString() + ":"+ _time.Second.ToString();
result += "\t";
result += _messageType.ToString();
result += "\t";
result += _sourceFile + ":" + _lineNumber.ToString();
result += " (";
result += _callingFunction;
result += ")";
result += "\t\t";
result += _message;
return result;
}
}
}
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
namespace CoatiSoftware.CoatiPlugin.Logging
{
public class Logging
{
public static void LogInfo(string message, [CallerFilePath] string file = "", [CallerMemberName] string member = "", [CallerLineNumber] int line = 0)
{
int idx = file.LastIndexOf('\\');
if(idx > -1)
{
file = file.Substring(idx + 1);
}
LogManager.GetInstance().LogInfo(message, file, member, line);
}
public static void LogWarning(string message, [CallerFilePath] string file = "", [CallerMemberName] string member = "", [CallerLineNumber] int line = 0)
{
int idx = file.LastIndexOf('\\');
if (idx > -1)
{
file = file.Substring(idx + 1);
}
LogManager.GetInstance().LogWarning(message, file, member, line);
}
public static void LogError(string message, [CallerFilePath] string file = "", [CallerMemberName] string member = "", [CallerLineNumber] int line = 0)
{
int idx = file.LastIndexOf('\\');
if (idx > -1)
{
file = file.Substring(idx + 1);
}
LogManager.GetInstance().LogError(message, file, member, line);
}
}
}
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
namespace CoatiSoftware.CoatiPlugin.Logging.Obfuscation
{
class NameObfuscator
{
private static NameObfuscator _instance = null;
private Dictionary<string, string> _dictionary = new Dictionary<string, string>();
private bool _enabled = false;
char _currentChar = 'a';
int _currentInt = 0;
private static string _directory = "";
private static string _fileNamePrefix = "Dictionary_CoatiPlugin_";
private static string _fileNameSufix = ".txt";
private string _fileName = "";
private Queue<string> _messageBacklog = new Queue<string>(); // stores messages if the log file was in use at original logging time
private NameObfuscator()
{
DateTime time = DateTime.Now;
string dateString = "";
dateString += time.Year.ToString() + "-" + time.Month.ToString() + "-" + time.Day.ToString() + "_";
dateString += time.Hour.ToString() + "-" + time.Minute.ToString() + "-" + time.Second.ToString();
_fileName = _fileNamePrefix + dateString + _fileNameSufix;
_directory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
_directory += "\\Coati Software\\Plugins\\VS\\";
if (System.IO.Directory.Exists(_directory) == false)
{
System.IO.Directory.CreateDirectory(_directory);
}
}
private static void CreateInstance()
{
if (_instance == null)
{
_instance = new NameObfuscator();
}
}
public static string GetObfuscatedName(string originalName)
{
CreateInstance();
if (_instance._enabled)
{
if (_instance._dictionary.ContainsKey(originalName))
{
return _instance._dictionary[originalName];
}
else
{
string newName = _instance.GetNewName();
_instance._dictionary[originalName] = newName;
_instance.WriteDictionaryEntryToFile(newName, originalName); // key and value reversed because that's the way the dictionary file is to be used...
return newName;
}
}
else
{
return originalName;
}
}
public static void Enabled(bool enabled)
{
CreateInstance();
_instance._enabled = enabled;
}
private string GetNewName()
{
string name = "";
name = _currentChar.ToString() + _currentInt.ToString();
++_currentChar;
if((int)_currentChar > 122)
{
_currentChar = 'a';
++_currentInt;
}
return name;
}
private void WriteDictionaryEntryToFile(string key, string value)
{
System.IO.StreamWriter writer = null;
string message = key + " - " + value;
try
{
writer = System.IO.File.AppendText(_directory + _fileName);
// write backlog to file first
while (_messageBacklog.Count > 0)
{
string bm = _messageBacklog.Dequeue();
writer.WriteLine(bm);
}
writer.WriteLine(message.ToString());
writer.Close();
}
catch (Exception e)
{
// well...file is still in use
_messageBacklog.Enqueue(message.ToString());
}
finally
{
if (writer != null)
{
writer.Close();
}
}
}
}
}
@@ -0,0 +1,80 @@
using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.Diagnostics;
namespace CoatiSoftware.CoatiPlugin.Logging
{
class VSOutputLogger : ILogger
{
private EnvDTE.DTE _dte = null;
private OutputWindowPane _pane = null;
public VSOutputLogger(EnvDTE.DTE dte)
{
_dte = dte;
}
public void LogMessage(LogMessage message)
{
if (message.MessageType == CoatiPlugin.Logging.LogMessage.LogMessageType.INFO)
{
Debug.WriteLine(message.Message, "Info");
WriteToOutputWindow("Info: " + message.Message);
}
if (message.MessageType == CoatiPlugin.Logging.LogMessage.LogMessageType.WARNING)
{
Debug.WriteLine(message.Message, "Warning");
WriteToOutputWindow("Warning: " + message.Message);
}
if (message.MessageType == CoatiPlugin.Logging.LogMessage.LogMessageType.ERROR)
{
Debug.WriteLine(message.Message, "Error");
WriteToOutputWindow("Error: " + message.Message);
}
}
private void WriteToOutputWindow(string message)
{
string paneName = "Coati Log";
if (_dte.Windows.Count > 0)
{
Window window = _dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
OutputWindow outputWindow = (OutputWindow)window.Object;
OutputWindowPanes panes = outputWindow.OutputWindowPanes;
if(_pane == null)
{
try
{
for (int i = 0; i < panes.Count; i++)
{
OutputWindowPane pane = panes.Item(i);
if (pane.Name.Equals(paneName, StringComparison.CurrentCultureIgnoreCase))
{
_pane = outputWindow.OutputWindowPanes.Item(i);
break;
}
}
}
catch (Exception e)
{
}
}
if (_pane == null)
{
_pane = outputWindow.OutputWindowPanes.Add(paneName);
}
_pane.OutputString(message + '\n');
}
}
}
}
@@ -14,6 +14,7 @@ namespace CoatiSoftware.CoatiPlugin
private static string s_endOfMessageToken = "<EOM>";
private static string s_createProjectPrefix = "createProject";
private static string s_createCDBProjectPrefix = "createCDBProject";
private static string s_ideId = "vs";
public class CursorPosition
@@ -86,6 +87,28 @@ namespace CoatiSoftware.CoatiPlugin
return message;
}
public static string createCreateProjectMessage(string cdbPath, List<string> headerPaths)
{
string message = s_createCDBProjectPrefix;
message += s_divider;
message += cdbPath;
message += s_divider;
foreach(string path in headerPaths)
{
message += path;
message += s_divider;
}
message += s_endOfMessageToken;
return message;
}
public static CursorPosition parseSetCursorMessage(string message)
{
CursorPosition result = new CursorPosition();
@@ -19,51 +19,22 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
static public List<string> _additionalCompileFlags = new List<string>();
// Creates a cdb from all projects in the solution
// For a more selective approach use 'CreateCommandObjects(...)' for per-project compile commands and assamble the cdb yourself
static public CompilationDatabase CreateCompilationDatabase(DTE dte, string configurationName, string platformName)
{
if(dte == null)
{
return null;
}
ReloadAll(dte);
CompilationDatabase compilationDatabase = new CompilationDatabase();
EnvDTE.Solution solution = dte.Solution;
EnvDTE.Projects projects = solution.Projects;
foreach (EnvDTE.Project project in projects)
{
List<CommandObject> cmdObjts = CreateCommandObjects(project, configurationName, platformName, "c11"); // TODO: retrieve real config/platform
foreach(CommandObject cmdObj in cmdObjts)
{
compilationDatabase.AddCommandObject(cmdObj);
}
}
UnloadReloadedProjects(dte);
return compilationDatabase;
}
static public List<string> _headerDirectories = new List<string>();
public static List<CommandObject> CreateCommandObjects(Project project, string configurationName, string platformName, string cStandard)
{
Logging.Logging.LogInfo("Creating command objects from project " + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name));
List<CommandObject> result = new List<CommandObject>();
DTE dte = project.DTE;
Guid projectGuid = Utility.SolutionUtility.ReloadProject(project);
string version = dte.Version;
Guid projectGuid = Utility.ProjectUtility.ReloadProject(project);
VCProject vcProject = project.Object as VCProject;
if (vcProject == null)
{
Logging.Logging.LogWarning("Project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "' could not be converted to VCProject, skipping.");
return result;
}
@@ -84,9 +55,11 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
VCConfiguration vcProjectConfig = GetProjectConfiguration(vcProject, configurationName, platformName);
string cppStandard = GetCppStandardString(vcProjectConfig);
Logging.Logging.LogInfo("Found C++ standard " + cppStandard + ".");
foreach (EnvDTE.ProjectItem item in projectItems)
{
CommandObject cmdObj = CreateCommandObject(item, includeDirectories, preprocessorDefinitions, cppStandard, cStandard);
CommandObject cmdObj = CreateCommandObject(item, includeDirectories, preprocessorDefinitions, cppStandard, cStandard, configurationName, platformName);
if (cmdObj != null)
{
result.Add(cmdObj);
@@ -95,15 +68,19 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
if(projectGuid != Guid.Empty)
{
Utility.SolutionUtility.UnloadProject(projectGuid, dte);
Utility.ProjectUtility.UnloadProject(projectGuid, dte);
}
_headerDirectories = _headerDirectories.Distinct().ToList();
return result;
}
static private Tuple<List<string>, List<string>> GetProjectIncludeDirectoriesAndPreprocessorDefs(VCProject project, string configurationName, string platformName)
{
List<string> includeDirectories = new List<string>();
Logging.Logging.LogInfo("Attempting to retreive Include Directories and Preprocessor Definitions for project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "'");
List <string> includeDirectories = new List<string>();
List<string> preprocessorDefinitions = new List<string>();
IEnumerable configurations = project.Configurations as IEnumerable;
@@ -148,26 +125,42 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
}
}
VCPlatform platform = vcProjectConfig.Platform as VCPlatform;
string platformIncludeDirectories = platform.IncludeDirectories;
string[] seperatedDirectories = platformIncludeDirectories.Split(';');
foreach (string directory in seperatedDirectories)
try
{
string resolvedDirectory = ResolveVSMacro(vcProjectConfig, directory);
string[] splitResolvedDirectory = resolvedDirectory.Split(';'); // resolved macros might result in concatenated paths
VCPlatform platform = vcProjectConfig.Platform as VCPlatform;
string platformIncludeDirectories = platform.IncludeDirectories;
string[] seperatedDirectories = platformIncludeDirectories.Split(';');
foreach (string p in splitResolvedDirectory)
foreach (string directory in seperatedDirectories)
{
includeDirectories.Add(p);
string resolvedDirectory = ResolveVSMacro(vcProjectConfig, directory);
string[] splitResolvedDirectory = resolvedDirectory.Split(';'); // resolved macros might result in concatenated paths
foreach (string p in splitResolvedDirectory)
{
includeDirectories.Add(p);
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return new Tuple<List<string>, List<string>>(new List<string>(), new List<string>());
}
}
else
{
Logging.Logging.LogWarning("Could not retreive Project Configuration. No include directories or preprocessor definitions could be retreived.");
return new Tuple<List<string>, List<string>>(new List<string>(), new List<string>());
}
includeDirectories = includeDirectories.Distinct().ToList();
preprocessorDefinitions = preprocessorDefinitions.Distinct().ToList();
Logging.Logging.LogInfo("Found " + includeDirectories.Count.ToString() + " distinct include directories and " + preprocessorDefinitions.Count.ToString() + " distinct preprocessor definitions.");
Logging.Logging.LogInfo("Attempting to resolve and clean up.");
for (int i = 0; i < includeDirectories.Count; i++)
{
string path = includeDirectories.ElementAt(i).Replace("\\", "/"); // backslashes would cause some string-escaping hassles...
@@ -204,6 +197,8 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
}
}
Logging.Logging.LogInfo("Found " + includeDirectories.Count.ToString() + " include directories and " + preprocessorDefinitions.Count.ToString() + " preprocessor definitions");
return new Tuple<List<string>, List<string>>(includeDirectories, preprocessorDefinitions);
}
@@ -227,101 +222,146 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
}
}
Logging.Logging.LogError("Failed to find project config matching with \"" + configurationName + "\"");
return null;
}
static private CommandObject CreateCommandObject(EnvDTE.ProjectItem item, List<string> includeDirectories, List<string> preprocessorDefinitions, string vcStandard, string cStandard)
static private CommandObject CreateCommandObject(EnvDTE.ProjectItem item, List<string> includeDirectories, List<string> preprocessorDefinitions, string vcStandard, string cStandard, string configurationName, string platformName)
{
DTE dte = item.DTE;
Logging.Logging.LogInfo("Starting to create Command Object from item '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(item.Name) + "'");
if (item.FileCodeModel != null && item.FileCodeModel.Language == CodeModelLanguageConstants.vsCMLanguageVC)
try
{
CommandObject commandObject = new CommandObject();
commandObject.File = item.Name;
DTE dte = item.DTE;
// only write source files to cdb, headers are implicit
if (CheckIsHeader(item))
if (dte == null)
{
return null;
Logging.Logging.LogError("Failed to retreive DTE object. Abort creating command object.");
}
VCFile vcFile = item.Object as VCFile;
string subType = vcFile.SubType;
VCProject project = vcFile.project;
VCConfiguration vcConfig = GetProjectConfiguration(project, "Release", "Win32");
VCFileConfiguration fc = vcFile.GetFileConfigurationForProjectConfiguration(vcConfig);
VCCLCompilerTool t = fc.Tool as VCCLCompilerTool;
string additionalOptions = t.AdditionalOptions;
CompileAsOptions compileAs = t.CompileAs; // VCCLCompilerToolShim
if(additionalOptions == "$(NOINHERIT)")
if (item.FileCodeModel != null && item.FileCodeModel.Language == CodeModelLanguageConstants.vsCMLanguageVC)
{
additionalOptions = "";
}
CommandObject commandObject = new CommandObject();
commandObject.File = item.Name;
// check wheter it's a .c file, we don't want that...
// TODO: there is a property for comilation as .c or .cpp file (/TC and /TP), try to retrieve it
string extension = item.Properties.Item("Extension").Value.ToString();
if (compileAs == CompileAsOptions.compileAsC)
// only write source files to cdb, headers are implicit
if (CheckIsHeader(item))
{
Properties props = item.Properties;
foreach (Property prop in props)
{
string propName = prop.Name;
string propValue = prop.Value as String;
if (propName == "FullPath")
{
int i = propValue.LastIndexOf('\\');
propValue = propValue.Substring(0, i);
_headerDirectories.Add(propValue);
}
}
return null;
}
VCFile vcFile = item.Object as VCFile;
string subType = vcFile.SubType;
VCProject project = vcFile.project;
VCConfiguration vcConfig = GetProjectConfiguration(project, configurationName, platformName);
if(vcConfig == null)
{
Logging.Logging.LogError("Project Configuration is null.");
return null;
}
VCFileConfiguration fc = vcFile.GetFileConfigurationForProjectConfiguration(vcConfig);
VCCLCompilerTool t = fc.Tool as VCCLCompilerTool;
string additionalOptions = t.AdditionalOptions;
CompileAsOptions compileAs = t.CompileAs; // VCCLCompilerToolShim
if (additionalOptions == "$(NOINHERIT)")
{
additionalOptions = "";
}
// check wheter it's a .c file, we don't want that...
// TODO: there is a property for comilation as .c or .cpp file (/TC and /TP), try to retrieve it
string extension = item.Properties.Item("Extension").Value.ToString();
if (compileAs == CompileAsOptions.compileAsC)
{
vcStandard = "-std=" + cStandard;
}
// if a language standard was defined in the additional options the 'vcStandard' string is not used
if (additionalOptions.Contains("-std="))
{
vcStandard = "";
}
string directory = item.Properties.Item("FullPath").Value.ToString();
int idx = directory.LastIndexOf('\\');
if (idx != -1)
{
directory = directory.Substring(0, idx + 1);
}
directory = directory.Replace('\\', '/');
commandObject.File = directory + item.Name;
commandObject.Directory = System.IO.Path.GetDirectoryName(dte.Solution.FullName); // TODO: replace with actual cdb location
commandObject.Directory = commandObject.Directory.Replace('\\', '/');
commandObject.Command = "clang-tool ";
foreach (string flag in _compatibilityFlags)
{
commandObject.Command += flag + " ";
}
commandObject.Command += _compatibilityVersionFlag + " ";
foreach (string dir in includeDirectories)
{
commandObject.Command += " -isystem '" + dir + "' "; // using '-isystem' because it allows for use of quotes and pointy brackets in source files. In other words it's more robust. It's slower than '-I' though
}
foreach (string prepDef in preprocessorDefinitions)
{
commandObject.Command += " -D " + prepDef + " ";
}
foreach (string flag in _additionalCompileFlags)
{
commandObject.Command += " -D " + flag + " ";
}
commandObject.Command += vcStandard + " ";
commandObject.Command += additionalOptions + " ";
commandObject.Command += "'" + commandObject.File + "'";
return commandObject;
}
else
{
vcStandard = "-std=" + cStandard;
Logging.Logging.LogInfo("Item discarded, wrong code model");
}
// if a language standard was defined in the additional options the 'vcStandard' string is not used
if(additionalOptions.Contains("-std="))
{
vcStandard = "";
}
string directory = item.Properties.Item("FullPath").Value.ToString();
int idx = directory.LastIndexOf('\\');
if (idx != -1)
{
directory = directory.Substring(0, idx + 1);
}
directory = directory.Replace('\\', '/');
commandObject.File = directory + item.Name;
commandObject.Directory = System.IO.Path.GetDirectoryName(dte.Solution.FullName); // TODO: replace with actual cdb location
commandObject.Directory = commandObject.Directory.Replace('\\', '/');
commandObject.Command = "clang-tool ";
foreach (string flag in _compatibilityFlags)
{
commandObject.Command += flag + " ";
}
commandObject.Command += _compatibilityVersionFlag + " ";
foreach (string dir in includeDirectories)
{
commandObject.Command += " -isystem '" + dir + "' "; // using '-isystem' because it allows for use of quotes and pointy brackets in source files. In other words it's more robust. It's slower than '-I' though
}
foreach (string prepDef in preprocessorDefinitions)
{
commandObject.Command += " -D " + prepDef + " ";
}
foreach(string flag in _additionalCompileFlags)
{
commandObject.Command += " -D " + flag + " ";
}
commandObject.Command += vcStandard + " ";
commandObject.Command += additionalOptions + " ";
commandObject.Command += "'" + commandObject.File + "'";
return commandObject;
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
Logging.Logging.LogError("Failed to create command object.");
return null;
}
@@ -332,21 +372,28 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
string propString = "";
foreach (Property prop in props)
try
{
string propName = prop.Name;
string propValue = prop.Value as String;
propString += propName + " - " + propValue + "; ";
if (propName == "ItemType")
foreach (Property prop in props)
{
if (propValue as String == "ClInclude")
string propName = prop.Name;
string propValue = prop.Value as String;
propString += propName + " - " + propValue + "; ";
if (propName == "ItemType")
{
return true;
if (propValue as String == "ClInclude")
{
return true;
}
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
return false;
}
@@ -355,15 +402,22 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
{
string result = path;
Tuple<int, int> potentialMacroPosition = Utility.StringUtility.FindFirstRange(path, "$(", ")");
if (potentialMacroPosition != null)
try
{
string potentialMacro = path.Substring(potentialMacroPosition.Item1, potentialMacroPosition.Item2 - potentialMacroPosition.Item1 + 1);
Tuple<int, int> potentialMacroPosition = Utility.StringUtility.FindFirstRange(path, "$(", ")");
string resolvedMacro = vcProjectConfig.Evaluate(potentialMacro);
if (potentialMacroPosition != null)
{
string potentialMacro = path.Substring(potentialMacroPosition.Item1, potentialMacroPosition.Item2 - potentialMacroPosition.Item1 + 1);
result = path.Substring(0, potentialMacroPosition.Item1) + resolvedMacro + path.Substring(potentialMacroPosition.Item2 + 1);
string resolvedMacro = vcProjectConfig.Evaluate(potentialMacro);
result = path.Substring(0, potentialMacroPosition.Item1) + resolvedMacro + path.Substring(potentialMacroPosition.Item2 + 1);
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
return result;
@@ -378,11 +432,11 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
EnvDTE.Solution solution = dte.Solution;
EnvDTE.Projects projects = solution.Projects;
List<EnvDTE.Project> projects = Utility.SolutionUtility.GetSolutionProjectList(dte);
foreach (EnvDTE.Project project in projects)
{
_reloadedProjectGuids.Add(Utility.SolutionUtility.ReloadProject(project));
_reloadedProjectGuids.Add(Utility.ProjectUtility.ReloadProject(project));
}
}
@@ -390,12 +444,14 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
{
foreach(Guid guid in _reloadedProjectGuids)
{
Utility.SolutionUtility.UnloadProject(guid, dte);
Utility.ProjectUtility.UnloadProject(guid, dte);
}
}
static private void SetCompatibilityVersionFlag(VCProject project, string configurationName, string platformName)
{
Logging.Logging.LogInfo("Determining CL.exe (C++ compiler) version");
VCConfiguration vcProjectConfig = GetProjectConfiguration(project, configurationName, platformName);
if (vcProjectConfig != null)
@@ -403,60 +459,88 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
IEnumerable projectTools = vcProjectConfig.Tools as IEnumerable;
foreach (Object tool in projectTools)
{
VCCLCompilerTool compilerTool = tool as VCCLCompilerTool;
if (compilerTool != null)
try
{
int majorCompilerVersion = GetCLMajorVersion(compilerTool, vcProjectConfig);
VCCLCompilerTool compilerTool = tool as VCCLCompilerTool;
if (majorCompilerVersion > -1)
if (compilerTool != null)
{
_compatibilityVersionFlag = _compatibilityVersionFlagBase + majorCompilerVersion.ToString();
return;
int majorCompilerVersion = GetCLMajorVersion(compilerTool, vcProjectConfig);
if (majorCompilerVersion > -1)
{
Logging.Logging.LogInfo("Found compiler version " + majorCompilerVersion.ToString());
_compatibilityVersionFlag = _compatibilityVersionFlagBase + majorCompilerVersion.ToString();
return;
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
}
}
else
{
Logging.Logging.LogWarning("Failed to retreive VC Project Configuration. Using default compiler version");
}
}
static private int GetCLMajorVersion(VCCLCompilerTool compilerTool, VCConfiguration vcProjectConfig)
{
if(compilerTool == null || vcProjectConfig == null)
Logging.Logging.LogInfo("Looking up CL.exe (C++ compiler)");
if (compilerTool == null || vcProjectConfig == null)
{
return -1;
}
VCPlatform platform = vcProjectConfig.Platform as VCPlatform;
string executableDirectories = platform.ExecutableDirectories;
string[] seperatedDirectories = executableDirectories.Split(';');
List<string> finalDirectories = new List<string>();
foreach (string directory in seperatedDirectories)
try
{
string resolvedDirectory = ResolveVSMacro(vcProjectConfig, directory);
string[] splitResolvedDirectory = resolvedDirectory.Split(';'); // resolved macros might result in concatenated paths
VCPlatform platform = vcProjectConfig.Platform as VCPlatform;
string executableDirectories = platform.ExecutableDirectories;
string[] seperatedDirectories = executableDirectories.Split(';');
foreach(string d in splitResolvedDirectory)
List<string> finalDirectories = new List<string>();
foreach (string directory in seperatedDirectories)
{
finalDirectories.Add(d);
string resolvedDirectory = ResolveVSMacro(vcProjectConfig, directory);
string[] splitResolvedDirectory = resolvedDirectory.Split(';'); // resolved macros might result in concatenated paths
foreach (string d in splitResolvedDirectory)
{
finalDirectories.Add(d);
}
}
string toolPath = compilerTool.ToolPath;
Logging.Logging.LogInfo("Found " + finalDirectories.Count.ToString() + " possible compiler directories.");
foreach (string fd in finalDirectories)
{
string path = fd + "\\" + toolPath;
if (File.Exists(path))
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(path);
int version = info.FileMajorPart;
Logging.Logging.LogInfo("Found compiler location. Compiler tool version is " + version.ToString());
return version;
}
}
}
string toolPath = compilerTool.ToolPath;
foreach(string fd in finalDirectories)
catch(Exception e)
{
string path = fd + "\\" + toolPath;
if(File.Exists(path))
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(path);
int version = info.FileMajorPart;
return version;
}
Logging.Logging.LogError("Exception: " + e.Message);
}
Logging.Logging.LogWarning("Failed to find C++ compiler tool.");
return -1;
}
@@ -472,27 +556,44 @@ namespace CoatiSoftware.CoatiPlugin.SolutionParser
string result = "";
IVCRulePropertyStorage rules = vcProjectConfig.Rules.Item("ConfigurationGeneral");
IVCRulePropertyStorage rules = null;
try
{
rules = vcProjectConfig.Rules.Item("ConfigurationGeneral");
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return "";
}
if (rules != null)
{
string toolset = rules.GetUnevaluatedPropertyValue("PlatformToolset");
string justNumbers = new String(toolset.Where(Char.IsDigit).ToArray());
int versionNumber = int.Parse(justNumbers);
if (versionNumber < 120) // version 11 (2012)
try
{
result = "-std=c++11";
string toolset = rules.GetUnevaluatedPropertyValue("PlatformToolset");
string justNumbers = new String(toolset.Where(Char.IsDigit).ToArray());
int versionNumber = int.Parse(justNumbers);
if (versionNumber < 120) // version 11 (2012)
{
result = "-std=c++11";
}
else if (versionNumber < 130) // version 12 (2013)
{
result = "-std=c++14";
}
else if (versionNumber < 150) // version 14 (2015)
{
result = "-std=c++14";
}
}
else if (versionNumber < 130) // version 12 (2013)
catch(Exception e)
{
result = "-std=c++14";
}
else if (versionNumber < 150) // version 14 (2015)
{
result = "-std=c++14";
Logging.Logging.LogError("Exception: " + e.Message);
}
}
@@ -21,10 +21,16 @@ namespace CoatiSoftware.CoatiPlugin.Utility
}
catch (Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
if (_errorCallback != null)
{
_errorCallback("Failed to open file at " + fileName);
}
string message = "Failed to open file at " + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName);
Logging.Logging.LogError(message);
return false;
}
}
@@ -37,9 +43,14 @@ namespace CoatiSoftware.CoatiPlugin.Utility
}
catch (Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
if (_errorCallback != null)
{
_errorCallback("Failed to set cursor to position [" + lineNumber.ToString() + "," + columnNumber.ToString() + "]");
string message = "Failed to set cursor to position [" + lineNumber.ToString() + "," + columnNumber.ToString() + "]";
Logging.Logging.LogError(message);
}
}
}
@@ -63,57 +63,75 @@ namespace CoatiSoftware.CoatiPlugin.Utility
}
catch (Exception e)
{
//if(_onErrorCallback != null)
//{
// _onErrorCallback(e.ToString());
//}
Logging.Logging.LogError("Exception: " + e.Message);
}
}
public static void AcceptCallback(IAsyncResult ar)
{
_allDone.Set();
try
{
_allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state._workSocket = handler;
handler.BeginReceive(state._buffer, 0, StateObject._bufferSize, 0, new AsyncCallback(ReadCallback), state);
StateObject state = new StateObject();
state._workSocket = handler;
handler.BeginReceive(state._buffer, 0, StateObject._bufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state._workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
try
{
state._stringBuilder.Append(Encoding.ASCII.GetString(state._buffer, 0, bytesRead));
string content = String.Empty;
content = state._stringBuilder.ToString();
if (content.IndexOf(_endOfMessageToken) > -1)
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state._workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
if (_onReadCallback != null)
state._stringBuilder.Append(Encoding.ASCII.GetString(state._buffer, 0, bytesRead));
content = state._stringBuilder.ToString();
if (content.IndexOf(_endOfMessageToken) > -1)
{
_onReadCallback(content);
if (_onReadCallback != null)
{
_onReadCallback(content);
}
}
else
{
handler.BeginReceive(state._buffer, 0, StateObject._bufferSize, 0, new AsyncCallback(ReadCallback), state);
}
}
else
{
handler.BeginReceive(state._buffer, 0, StateObject._bufferSize, 0, new AsyncCallback(ReadCallback), state);
}
}
catch(Exception e)
{
Logging.Logging.LogError("Excpetion: " + e.Message);
}
}
private static void Send(Socket handler, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
try
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
catch(Exception e)
{
Logging.Logging.LogError("Excpetion: " + e.Message);
}
}
private static void SendCallback(IAsyncResult ar)
@@ -123,10 +141,12 @@ namespace CoatiSoftware.CoatiPlugin.Utility
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
Logging.Logging.LogInfo("Sent " + bytesSent.ToString() + " bytes to client.");
}
catch (Exception e)
{
Logging.Logging.LogError("Excpetion: " + e.Message);
if (_onErrorCallback != null)
{
_onErrorCallback(e.ToString());
@@ -159,6 +179,9 @@ namespace CoatiSoftware.CoatiPlugin.Utility
client.EndConnect(ar);
client.Shutdown(SocketShutdown.Both);
client.Close();
Logging.Logging.LogWarning("Connection timed out, message was not sent");
return;
}
@@ -186,6 +209,8 @@ namespace CoatiSoftware.CoatiPlugin.Utility
}
catch (Exception e)
{
Logging.Logging.LogError("Excpetion: " + e.Message);
if (_onErrorCallback != null)
{
_onErrorCallback(e.ToString());
@@ -195,9 +220,16 @@ namespace CoatiSoftware.CoatiPlugin.Utility
private static void Send(Socket client, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
try
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
}
private static void SendCallback(IAsyncResult ar)
@@ -212,6 +244,8 @@ namespace CoatiSoftware.CoatiPlugin.Utility
}
catch (Exception e)
{
Logging.Logging.LogError("Excpetion: " + e.Message);
if (_onErrorCallback != null)
{
if (e is ObjectDisposedException)
@@ -221,6 +255,7 @@ namespace CoatiSoftware.CoatiPlugin.Utility
}
else
{
_onErrorCallback(e.ToString());
}
}
@@ -1,4 +1,8 @@
using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -10,17 +14,24 @@ namespace CoatiSoftware.CoatiPlugin.Utility
{
List<ProjectItem> projectItems = GetProjectItems(project);
foreach (EnvDTE.ProjectItem item in projectItems)
try
{
if (item.FileCodeModel != null && item.FileCodeModel.Language == CodeModelLanguageConstants.vsCMLanguageVC)
foreach (EnvDTE.ProjectItem item in projectItems)
{
string extension = item.Properties.Item("Extension").Value.ToString();
if (extension == ".c")
if (item.FileCodeModel != null && item.FileCodeModel.Language == CodeModelLanguageConstants.vsCMLanguageVC)
{
return true;
string extension = item.Properties.Item("Extension").Value.ToString();
if (extension == ".c")
{
return true;
}
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
return false;
}
@@ -34,13 +45,13 @@ namespace CoatiSoftware.CoatiPlugin.Utility
while (itemEnumerator.MoveNext())
{
ProjectItem currentItem = (ProjectItem)itemEnumerator.Current;
items.Add(GetProjectItemsRecursive(currentItem, ref items));
items.Add(GetProjectSubItemsRecursive(currentItem, ref items));
}
return items;
}
static private ProjectItem GetProjectItemsRecursive(ProjectItem item, ref List<ProjectItem> projectItems)
static private ProjectItem GetProjectSubItemsRecursive(ProjectItem item, ref List<ProjectItem> projectItems)
{
if (item.ProjectItems == null)
{
@@ -52,10 +63,104 @@ namespace CoatiSoftware.CoatiPlugin.Utility
while (items.MoveNext())
{
ProjectItem currentItem = (ProjectItem)items.Current;
projectItems.Add(GetProjectItemsRecursive(currentItem, ref projectItems));
projectItems.Add(GetProjectSubItemsRecursive(currentItem, ref projectItems));
}
return item;
}
// returns true if the project was reloaded, false if the project did not need to be reloaded
static public Guid ReloadProject(Project project)
{
Logging.Logging.LogInfo("Attempting to reload project");
try
{
if (project != null && project.Kind == EnvDTE.Constants.vsProjectKindUnmodeled)
{
DTE dte = project.DTE;
ServiceProvider sp = new ServiceProvider(dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsSolution vsSolution = sp.GetService(typeof(SVsSolution)) as IVsSolution;
IVsHierarchy hierarchy;
string solutionDirectory = "";
string solutionFile = "";
string userOptions = "";
vsSolution.GetSolutionInfo(out solutionDirectory, out solutionFile, out userOptions);
vsSolution.GetProjectOfUniqueName(solutionDirectory + project.UniqueName, out hierarchy);
if (hierarchy != null)
{
Guid projectGuid;
hierarchy.GetGuidProperty(
VSConstants.VSITEMID_ROOT,
(int)__VSHPROPID.VSHPROPID_ProjectIDGuid,
out projectGuid);
if (projectGuid != null)
{
Logging.Logging.LogInfo("Project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "' with GUID {" + projectGuid.ToString() + "} loaded.");
(vsSolution as IVsSolution4).ReloadProject(projectGuid);
return projectGuid;
}
else
{
Logging.Logging.LogError("Failed to load project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "'");
}
}
else
{
Logging.Logging.LogError("Failed to retreive IVsHierarchy. Can't load project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "'");
}
}
else
{
if (project == null)
{
Logging.Logging.LogWarning("Project is null");
}
else
{
Logging.Logging.LogInfo("Project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "' is already loaded");
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return Guid.Empty;
}
return Guid.Empty;
}
static public void UnloadProject(Guid guid, DTE dte)
{
Logging.Logging.LogInfo("Attempting to unload project with GUID {" + guid.ToString() + "}");
if (dte == null)
{
return;
}
try
{
ServiceProvider sp = new ServiceProvider(dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsSolution vsSolution = sp.GetService(typeof(SVsSolution)) as IVsSolution;
(vsSolution as IVsSolution4).UnloadProject(guid, (uint)_VSProjectUnloadStatus.UNLOADSTATUS_UnloadedByUser);
Logging.Logging.LogInfo("Done unloading project with GUID {" + guid.ToString() + "}");
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
}
}
}
@@ -55,9 +55,18 @@ namespace CoatiSoftware.CoatiPlugin.Utility
public static String GetSolutionPath(DTE dte)
{
EnvDTE.Solution solution = dte.Solution;
try
{
EnvDTE.Solution solution = dte.Solution;
return solution.FullName;
return solution.FullName;
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return "N/A";
}
}
public static SolutionStructure GetSolutionVCProjects(DTE dte)
@@ -76,34 +85,48 @@ namespace CoatiSoftware.CoatiPlugin.Utility
foreach(Project project in solutionProjects)
{
if(project.Kind == EnvDTE.Constants.vsProjectKindUnmodeled) // not loaded
try
{
continue;
}
// check it's a c/c++ project
if(project.CodeModel != null)
{
if(project.CodeModel.Language != CodeModelLanguageConstants.vsCMLanguageVC)
if (project.Kind == EnvDTE.Constants.vsProjectKindUnmodeled) // not loaded
{
continue;
}
// check it's a c/c++ project
if (project.CodeModel != null)
{
if (project.CodeModel.Language != CodeModelLanguageConstants.vsCMLanguageVC)
{
continue;
}
}
if (project.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
{
SolutionStructure.ProjectNode projectNode = new SolutionStructure.ProjectNode();
projectNode.Name = project.Name;
projectNode.Project = project;
projectNode.Include = false;
projectStructure.Nodes.Add(projectNode);
}
else
{
SolutionStructure.Node folderNode = GetSubProjects(project);
if (folderNode != null)
{
projectStructure.Nodes.Add(folderNode);
}
else
{
Logging.Logging.LogWarning("Subnode was NULL");
}
}
}
if(project.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
catch(Exception e)
{
SolutionStructure.ProjectNode projectNode = new SolutionStructure.ProjectNode();
projectNode.Name = project.Name;
projectNode.Project = project;
projectNode.Include = false;
projectStructure.Nodes.Add(projectNode);
}
else
{
SolutionStructure.Node folderNode = GetSubProjects(project);
projectStructure.Nodes.Add(folderNode);
Logging.Logging.LogError("Exception: " + e.Message);
}
}
@@ -115,41 +138,58 @@ namespace CoatiSoftware.CoatiPlugin.Utility
ProjectItems projectItems = project.ProjectItems;
List<Project> items = new List<Project>();
foreach (ProjectItem item in projectItems)
try
{
Project p = item.Object as Project;
if(p != null)
foreach (ProjectItem item in projectItems)
{
items.Add(p);
}
}
if(items.Count > 0)
{
SolutionStructure.FolderNode folderNode = new SolutionStructure.FolderNode();
folderNode.Name = project.Name;
for (int i = 0; i < items.Count; i++)
{
Project item = items[i];
SolutionStructure.Node subFolderNode = GetSubProjects(item);
folderNode.SubNodes.Add(subFolderNode);
Project p = item.Object as Project;
if (p != null)
{
items.Add(p);
}
}
return folderNode;
}
else
{
SolutionStructure.ProjectNode projectNode = new SolutionStructure.ProjectNode();
projectNode.Name = project.Name;
projectNode.Project = project;
projectNode.Include = false;
if (items.Count > 0)
{
SolutionStructure.FolderNode folderNode = new SolutionStructure.FolderNode();
folderNode.Name = project.Name;
return projectNode;
for (int i = 0; i < items.Count; i++)
{
Project item = items[i];
SolutionStructure.Node subFolderNode = GetSubProjects(item);
if(subFolderNode != null)
{
folderNode.SubNodes.Add(subFolderNode);
}
else
{
Logging.Logging.LogWarning("SubNode was NULL");
}
}
return folderNode;
}
else
{
SolutionStructure.ProjectNode projectNode = new SolutionStructure.ProjectNode();
projectNode.Name = project.Name;
projectNode.Project = project;
projectNode.Include = false;
return projectNode;
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return null;
}
}
// Deprecated: remove when old project parsing is retired
public static List<String> GetSolutionProjectsFullNames(DTE dte)
{
List<String> projectNames = new List<String>();
@@ -161,7 +201,7 @@ namespace CoatiSoftware.CoatiPlugin.Utility
foreach (EnvDTE.Project project in projects)
{
guids.Add(ReloadProject(project));
guids.Add(ProjectUtility.ReloadProject(project));
}
projects = solution.Projects;
@@ -173,45 +213,17 @@ namespace CoatiSoftware.CoatiPlugin.Utility
foreach (Guid guid in guids)
{
UnloadProject(guid, dte);
ProjectUtility.UnloadProject(guid, dte);
}
return projectNames;
}
public static List<List<String>> GetSolutionProjectItems(DTE dte)
{
List<List<String>> projectItems = new List<List<String>>();
EnvDTE.Solution solution = dte.Solution;
EnvDTE.Projects projects = solution.Projects;
foreach (EnvDTE.Project project in projects)
{
EnvDTE.ProjectItems items = project.ProjectItems;
List<String> pItems = new List<String>();
foreach(EnvDTE.ProjectItem item in items)
{
for (short i = 0; i < item.FileCount; i++)
{
pItems.Add(item.get_FileNames(i));
}
}
projectItems.Add(pItems);
}
return projectItems;
}
public static List<String> GetSolutionLanguages(DTE dte)
{
List<String> languages = new List<String>();
EnvDTE.Solution solution = dte.Solution;
EnvDTE.Projects projects = solution.Projects;
List<Project> projects = GetSolutionProjectList(dte);
foreach (EnvDTE.Project project in projects)
{
@@ -229,9 +241,18 @@ namespace CoatiSoftware.CoatiPlugin.Utility
public static bool GetSolutionIsSaved(DTE dte)
{
EnvDTE.Solution solution = dte.Solution;
try
{
EnvDTE.Solution solution = dte.Solution;
return solution.Saved;
return solution.Saved;
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
throw e;
}
}
public static List<List<string>> GetConfigurationAndPlatformNames(DTE dte)
@@ -259,125 +280,84 @@ namespace CoatiSoftware.CoatiPlugin.Utility
return result;
}
foreach (SolutionConfiguration2 solutionConfiguration in solutionBuild.SolutionConfigurations)
try
{
foreach (SolutionContext context in solutionConfiguration.SolutionContexts)
foreach (SolutionConfiguration2 solutionConfiguration in solutionBuild.SolutionConfigurations)
{
string configurationName = context.ConfigurationName;
configNames.Add(configurationName);
foreach (SolutionContext context in solutionConfiguration.SolutionContexts)
{
string configurationName = context.ConfigurationName;
configNames.Add(configurationName);
string platformName = context.PlatformName;
platformNames.Add(platformName);
string platformName = context.PlatformName;
platformNames.Add(platformName);
}
}
configNames = configNames.Distinct().ToList();
platformNames = platformNames.Distinct().ToList();
result.Add(configNames);
result.Add(platformNames);
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
configNames = configNames.Distinct().ToList();
platformNames = platformNames.Distinct().ToList();
result.Add(configNames);
result.Add(platformNames);
return result;
}
public static DTE2 GetDTE2(DTE dte)
{
List<DTE2> dte2List = new List<DTE2>();
IRunningObjectTable runningObjectTable = null;
GetRunningObjectTable(0, out runningObjectTable);
IEnumMoniker enumMoniker = null;
runningObjectTable.EnumRunning(out enumMoniker);
enumMoniker.Reset();
IntPtr fetched = IntPtr.Zero;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, fetched) == 0)
try
{
IBindCtx bindCtx = null;
CreateBindCtx(0, out bindCtx);
List<DTE2> dte2List = new List<DTE2>();
string displayName = "";
moniker[0].GetDisplayName(bindCtx, null, out displayName);
// add all VisualStudio ROT entries to list
if (displayName.StartsWith("!VisualStudio"))
IRunningObjectTable runningObjectTable = null;
GetRunningObjectTable(0, out runningObjectTable);
IEnumMoniker enumMoniker = null;
runningObjectTable.EnumRunning(out enumMoniker);
enumMoniker.Reset();
IntPtr fetched = IntPtr.Zero;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, fetched) == 0)
{
object comObject;
runningObjectTable.GetObject(moniker[0], out comObject);
dte2List.Add((DTE2)comObject);
}
}
IBindCtx bindCtx = null;
CreateBindCtx(0, out bindCtx);
// find the correct dte2 instance (each running VS instance has one...)
KeyValuePair<DTE2, int> maxMatch = new KeyValuePair<DTE2, int>(null, 0);
foreach(DTE2 dte2 in dte2List)
{
int m = StringUtility.GetMatchingCharsFromStart(dte.Solution.FullName, dte2.Solution.FullName);
if(m > maxMatch.Value)
{
maxMatch = new KeyValuePair<DTE2, int>(dte2, m);
}
}
return maxMatch.Key;
}
// returns true if the project was reloaded, false if the project did not need to be reloaded
static public Guid ReloadProject(Project project)
{
if (project != null && project.Kind == EnvDTE.Constants.vsProjectKindUnmodeled)
{
DTE dte = project.DTE;
ServiceProvider sp = new ServiceProvider(dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsSolution vsSolution = sp.GetService(typeof(SVsSolution)) as IVsSolution;
IVsHierarchy hierarchy;
string solutionDirectory = "";
string solutionFile = "";
string userOptions = "";
vsSolution.GetSolutionInfo(out solutionDirectory, out solutionFile, out userOptions);
vsSolution.GetProjectOfUniqueName(solutionDirectory + project.UniqueName, out hierarchy);
if (hierarchy != null)
{
Guid projectGuid;
hierarchy.GetGuidProperty(
VSConstants.VSITEMID_ROOT,
(int)__VSHPROPID.VSHPROPID_ProjectIDGuid,
out projectGuid);
if (projectGuid != null)
string displayName = "";
moniker[0].GetDisplayName(bindCtx, null, out displayName);
// add all VisualStudio ROT entries to list
if (displayName.StartsWith("!VisualStudio"))
{
(vsSolution as IVsSolution4).ReloadProject(projectGuid);
return projectGuid;
object comObject;
runningObjectTable.GetObject(moniker[0], out comObject);
dte2List.Add((DTE2)comObject);
}
}
// find the correct dte2 instance (each running VS instance has one...)
KeyValuePair<DTE2, int> maxMatch = new KeyValuePair<DTE2, int>(null, 0);
foreach (DTE2 dte2 in dte2List)
{
int m = StringUtility.GetMatchingCharsFromStart(dte.Solution.FullName, dte2.Solution.FullName);
if (m > maxMatch.Value)
{
maxMatch = new KeyValuePair<DTE2, int>(dte2, m);
}
}
return maxMatch.Key;
}
return Guid.Empty;
}
static public void UnloadProject(Guid guid, DTE dte)
{
if (dte == null)
catch(Exception e)
{
return;
Logging.Logging.LogError("Exception: " + e.Message);
return null;
}
EnvDTE.Solution solution = dte.Solution;
EnvDTE.Projects projects = solution.Projects;
ServiceProvider sp = new ServiceProvider(dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsSolution vsSolution = sp.GetService(typeof(SVsSolution)) as IVsSolution;
(vsSolution as IVsSolution4).UnloadProject(guid, (uint)_VSProjectUnloadStatus.UNLOADSTATUS_UnloadedByUser);
}
static public bool ContainsCFiles(DTE dte)
@@ -399,35 +379,44 @@ namespace CoatiSoftware.CoatiPlugin.Utility
{
List<EnvDTE.Project> solutionProjects = new List<EnvDTE.Project>();
SolutionStructure solutionStructure = GetProjectStructureRecursive(dte);
Stack<SolutionStructure.Node> nodeStack = new Stack<Utility.SolutionUtility.SolutionStructure.Node>();
foreach (SolutionStructure.Node node in solutionStructure.Nodes)
try
{
nodeStack.Push(node);
}
SolutionStructure solutionStructure = GetProjectStructureRecursive(dte);
while (nodeStack.Count > 0)
{
Utility.SolutionUtility.SolutionStructure.Node node = nodeStack.Pop();
string name = node.Name;
if (node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.PROJECT)
Stack<SolutionStructure.Node> nodeStack = new Stack<Utility.SolutionUtility.SolutionStructure.Node>();
foreach (SolutionStructure.Node node in solutionStructure.Nodes)
{
solutionProjects.Add(node.Project);
nodeStack.Push(node);
}
else if (node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.FOLDER)
while (nodeStack.Count > 0)
{
Utility.SolutionUtility.SolutionStructure.FolderNode folderNode = node as Utility.SolutionUtility.SolutionStructure.FolderNode;
foreach (Utility.SolutionUtility.SolutionStructure.Node subNode in folderNode.SubNodes)
Utility.SolutionUtility.SolutionStructure.Node node = nodeStack.Pop();
string name = node.Name;
if (node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.PROJECT)
{
nodeStack.Push(subNode);
solutionProjects.Add(node.Project);
}
else if (node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.FOLDER)
{
Utility.SolutionUtility.SolutionStructure.FolderNode folderNode = node as Utility.SolutionUtility.SolutionStructure.FolderNode;
foreach (Utility.SolutionUtility.SolutionStructure.Node subNode in folderNode.SubNodes)
{
nodeStack.Push(subNode);
}
}
}
}
return solutionProjects;
return solutionProjects;
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return new List<EnvDTE.Project>();
}
}
}
}
@@ -11,13 +11,20 @@ namespace CoatiSoftware.CoatiPlugin.Utility
public static void GetWindowFocus()
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
IntPtr windowHandle = process.MainWindowHandle;
if (windowHandle != null)
try
{
SetForegroundWindow(windowHandle);
SetActiveWindow(windowHandle);
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
IntPtr windowHandle = process.MainWindowHandle;
if (windowHandle != null)
{
SetForegroundWindow(windowHandle);
SetActiveWindow(windowHandle);
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
}
}
@@ -56,6 +56,8 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
public void UpdateGUI()
{
Logging.Logging.LogInfo("Populating GUI");
InitProjectCheckList();
InitComboBoxConfigurations();
InitComboBoxPlatforms();
@@ -66,6 +68,8 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
private void InitComboBoxConfigurations()
{
Logging.Logging.LogInfo("Adding " + m_configurations.Count.ToString() + " build configurations.");
foreach(string configuration in m_configurations)
{
comboBoxConfiguration.Items.Add(configuration);
@@ -79,7 +83,9 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
private void InitComboBoxPlatforms()
{
foreach(string platform in m_platforms)
Logging.Logging.LogInfo("Adding " + m_platforms.Count.ToString() + " target platforms.");
foreach (string platform in m_platforms)
{
comboBoxPlatform.Items.Add(platform);
}
@@ -141,6 +147,8 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
private void InitTextBoxTargetDirectory()
{
Logging.Logging.LogInfo("Setting default target directory: \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(m_solutionDirectory) + "\"");
folderBrowserTargetDirectory.SelectedPath = m_solutionDirectory;
string rootDirectory = folderBrowserTargetDirectory.SelectedPath.ToString();
textBoxTargetDirectory.Text = rootDirectory;
@@ -148,20 +156,24 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
private void InitTextBoxFileName()
{
textBoxFileName.Text = m_solutionFileName;
Logging.Logging.LogInfo("Setting default file name: '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(m_solutionFileName) + "'");
// MakeFileNameUnique();
textBoxFileName.Text = m_solutionFileName;
}
private void InitComboBoxCStandard()
{
if(m_containsCFiles == false)
{
Logging.Logging.LogInfo("Hiding C Standard selection");
comboBoxCStandard.Hide();
labelCStandard.Hide();
}
else
{
Logging.Logging.LogInfo("Showing C Standard selection");
comboBoxCStandard.Show();
labelCStandard.Show();
@@ -176,6 +188,8 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
private void buttonCancel_Click(object sender, EventArgs e)
{
Logging.Logging.LogInfo("Close button pressed. Aborting.");
Close();
}
@@ -186,6 +200,8 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
private void OnCreate()
{
Logging.Logging.LogInfo("Create button pressed");
if (m_onCreateProject != null)
{
string configurationName = "";
@@ -194,16 +210,21 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
configurationName = comboBoxConfiguration.SelectedItem as string;
platformName = comboBoxPlatform.SelectedItem as string;
Logging.Logging.LogInfo("Configuration " + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(configurationName) + "|" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(platformName) + " was selected.");
string targetDir = textBoxTargetDirectory.Text;
if(Directory.Exists(targetDir) && CheckFileNameIsValid(textBoxFileName.Text))
{
if (CheckFileExists())
{
Logging.Logging.LogWarning("A file \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(targetDir + "\\" + textBoxFileName.Text) + "\" already exists.");
DialogResult result = MessageBox.Show("A file of the chosen name already exists. Do you want to replace it?", "Coati Plugin", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if(result == DialogResult.No)
{
Logging.Logging.LogInfo("Aborting CDB creation and attempting to make file name unique.");
MakeFileNameUnique();
return;
}
@@ -215,6 +236,8 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
cStandard = comboBoxCStandard.SelectedItem as string;
}
Logging.Logging.LogInfo("Setting C standard flag to " + cStandard);
m_onCreateProject(GetTreeViewProjectItems(), configurationName, platformName, targetDir, textBoxFileName.Text, cStandard);
Close();
}
@@ -222,15 +245,21 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
{
if(Directory.Exists(targetDir) == false)
{
Logging.Logging.LogError("The target directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(targetDir) + "\" does not exist.");
MessageBox.Show("The target directory does not exist.", "Coati Plugin", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
if (CheckFileNameIsValid(textBoxFileName.Text) == false)
{
Logging.Logging.LogError("The chosen file name \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(textBoxFileName.Text) + "\" is not valid. I'd almost dare to say it's invalid!");
MessageBox.Show("The chosen file name is not valid.", "Coati Plugin", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
else
{
Logging.Logging.LogError("CDB create callback is not set. Cannot start creating CDB.");
}
}
private bool CheckFileNameIsValid(string fileName)
@@ -12,7 +12,15 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
{
public partial class WindowCreateCDB : Form
{
public delegate void OnFinishedCreatingCDB(SolutionParser.CompilationDatabase cdb, string directory, string fileName);
public struct CreationResult
{
public SolutionParser.CompilationDatabase _cdb;
public string _cdbDirectory;
public string _cdbName;
public List<string> _headerDirectories;
}
public delegate void OnFinishedCreatingCDB(CreationResult result);
private OnFinishedCreatingCDB m_onFinishedCreateCDB = null;
@@ -24,7 +32,7 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
string m_fileName = "";
string m_cStandard = "";
SolutionParser.CompilationDatabase m_cdb = null;
CreationResult m_result = new CreationResult();
public OnFinishedCreatingCDB CallbackOnFinishedCreatingCDB
{
@@ -86,18 +94,30 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
backgroundWorker1.RunWorkerAsync();
}
private SolutionParser.CompilationDatabase CreateCDB()
private CreationResult CreateCDB()
{
CreationResult result = new CreationResult();
result._cdb = null;
result._cdbDirectory = "";
result._cdbName = "";
result._headerDirectories = new List<string>();
Logging.Logging.LogInfo("Starting to create CDB");
SolutionParser.CompilationDatabase cdb = new SolutionParser.CompilationDatabase();
int projectsProcessed = 0;
List<string> headerDirectories = new List<string>();
SolutionParser.SolutionParser._headerDirectories.Clear();
foreach (EnvDTE.Project project in m_projects)
{
List<SolutionParser.CommandObject> commandObjects = SolutionParser.SolutionParser.CreateCommandObjects(project, m_configurationName, m_platformName, m_cStandard);
projectsProcessed++;
float relativProgress = (float)projectsProcessed/(float)m_projects.Count;
Logging.Logging.LogInfo("Processing project \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "\"");
backgroundWorker1.ReportProgress((int)(relativProgress * 100), "Processing project \"" + project.Name + "\"");
foreach (SolutionParser.CommandObject obj in commandObjects)
@@ -106,30 +126,52 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
}
}
return cdb;
headerDirectories = SolutionParser.SolutionParser._headerDirectories;
result._cdb = cdb;
result._cdbDirectory = m_targetDir;
result._cdbName = m_fileName;
result._headerDirectories = headerDirectories;
Logging.Logging.LogInfo("Done creating CDB");
return result;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
m_cdb = CreateCDB();
m_result = CreateCDB();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
labelStatus.Text = e.UserState as string;
if(backgroundWorker1.CancellationPending == false)
{
progressBar.Value = e.ProgressPercentage;
labelStatus.Text = e.UserState as string;
}
else
{
progressBar.Value = 0;
labelStatus.Text = "Cancelling...";
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Cancelled == false && e.Error == null)
if(e.Cancelled == false && e.Error == null && progressBar.Value >= 100)
{
if (m_onFinishedCreateCDB != null)
{
m_onFinishedCreateCDB(m_cdb, m_targetDir, m_fileName);
m_onFinishedCreateCDB(m_result);
}
}
else
{
Logging.Logging.LogWarning("CDB creation was aborted by user");
}
Close();
}
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="acf15780-03b5-440e-a41e-db79b7043fc2" Version="0.8.12" Language="en-US" Publisher="Coati Software OG" />
<Identity Id="acf15780-03b5-440e-a41e-db79b7043fc2" Version="0.8.18" Language="en-US" Publisher="Coati Software OG" />
<DisplayName>CoatiPlugin</DisplayName>
<Description xml:space="preserve">This package allows Coati to communicate with Visual Studio and vice versa.</Description>
<MoreInfo>https://www.coati.io/</MoreInfo>