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:
@@ -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
|
||||
@@ -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>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
@@ -1856,7 +1856,61 @@
|
||||
</table>
|
||||
|
||||
<p>Once the CDB was successfully created it can be found in the specified target directory. From this CDB you can create a Coati project as <a href="#CreateAProjectFromCompilationDatabase">described above</a>.</p>
|
||||
|
||||
<strong>Settings</strong>
|
||||
<p>Network settings and logging options can be changed in the plugin's Tools/Options entry.</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<img src="img/vs_plugin_ports_0.png" >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p></p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<img src="img/vs_plugin_options.png" >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p></p>
|
||||
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr> <th>Option</th> <th>Description</th> </tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr> <th scope="row">Coati Port</th> <td>The port on which Coati will receive messages. Note that this must match the port setting in Coati itself.</td> </tr>
|
||||
<tr> <th scope="row">VS Port</th> <td>The port on which Visual Studio will receive messages. Note that this must match the port setting in Coati itself.</td> </tr>
|
||||
<tr> <th scope="row">File Logging</th> <td>Enable log output for the plugin. Additionaly to the output file, log messages will also be displayed in VS' </td> </tr>
|
||||
<tr> <th Id="vsPluginOptionObfuscation" scope="row">Log Obfuscation</th> <td>Obfuscate project- and file names as well as directories in the log output. Note that already logged data <b>will not be obfuscated retroactively</b>. A dictionary, mapping obfuscated names to original names, will be created in a seperate file.</td> </tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<strong>Logging</strong>
|
||||
<!-- File logging -->
|
||||
<p>The plugin offers optional file logging. Should you ever have problems with the plugin we recommend to turn logging on. This will help to pinpoint and resolve the issue faster.</p>
|
||||
<p>Logs will be created in <code>..\AppData\Local\Coati Software\Plugins\VS</code> folder. A new log file will be created every time you restart VS and logging is enabled.</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<img src="img/vs_log_folder.png" >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Obfuscation -->
|
||||
<p>Note that the logs will include project- and file names as well as directories specific to your project. If you wish to keep this informatin secret you can use <a href="#vsPluginOptionObfuscation">log obfuscation</a>.</p>
|
||||
<p>Project- and file names as well as directories will be replaced by an alphanumeric sequence. The sequence has the form <code>a0, b0, c0,..., a1, b1, c1,...</code>. Note that after switching on obfuscation, already logged data <b>will not be obfuscated retroactively</b>. No log files will be send to Coati Software automatically. You can check any file you may want to send us for sensible information before sending it.</p>
|
||||
<p>A dictionary, mapping obfuscated names to original names, will be created in your log folder if log obfuscation is switched on. When during the support process we refer to project items by their obfuscated name you can still make sense of it. <b>Do not send the dictionary to anybody else</b>.</p>
|
||||
|
||||
<!-- Console logging -->
|
||||
<p>Lastly, log messages are also displayed in the VS output window. This is tied to file logging and is not en- or disabled separately.</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-sm-offset-2">
|
||||
<img src="img/vs_output_window.png" >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- .span9 !-->
|
||||
</div> <!-- .row !-->
|
||||
</div> <!-- .container-fluid !-->
|
||||
|
||||
Reference in New Issue
Block a user