Open DTE solution from another program (not add-in) - visual-studio-2010

Is it possible to modify a solution, and use envdte tools, from a command-line project ?
I have an add-in that modifies a solution. But... the changes are required for over a hundred projects... So I'd like to make a c# program that has the same logic, only it iterates through all solution files.
The add-in starts with
EnvDTE.Solution solution = (EnvDTE.Solution)application.Solution;
where DTE2 application is passed from the add-in...
How can I get the same solution, which then I query for projects...
From a separate program, that will only know the solutionPath ?
Is it possible to open the solution, process it, and close it - to move on to the next solution ?
Microsoft gives this example http://msdn.microsoft.com/en-us/library/envdte._solution.open(v=vs.100).aspx
But I don't know what dte is in the context...
Thank you...
VS 2010
edit: I did what the answer below suggests.
Slightly modified, using the link:
http://msdn.microsoft.com/en-us/library/ms228772(v=vs.100).aspx
Thank you

Yes you can. You just need to activate an instance using the COM CLSID for Visual Studio. An example is below. It actually creates a solution and adds two projects to it but the same initialization applies when opening an existing solution.
A couple of caveats:
Mind the COM threading model. The code created from the console app template is sufficient:
[STAThread]
static void Main()
If you have a powerful VS extension like ReSharper installed, you might be better off suspending it if you don't need it for the VS automation. ReSharper had VS commands that control it.
Console.WriteLine("Opening Visual Studio");
var dte = (DTE)Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.DTE.10.0",true),true);
Console.WriteLine("Suspending Resharper");
dte.ExecuteCommand("ReSharper_Suspend");
Console.WriteLine("Working with {0}, {1} edition", dte.FullName, dte.Edition);
dte.SuppressUI = true;
dte.UserControl = false;
foreach (var solution in mySolutionInfoList)
{
try
{
dte.Solution.Create(solution.directory, solution.name);
dte.Solution.AddFromTemplate(csharpTemplatePath, solution.directory + "ClassLibrary1", "ClassLibrary1");
dte.Solution.AddFromTemplate(vcTemplatePath, solution.directory + "Win32Dll", "Win32Dll");
Directory.CreateDirectory(solution.directory); // ensure directory exists. Otherwise, user will be asked for save location, regardless of SupressUI value
dte.Solution.Close(true);
Console.WriteLine();
}
catch (Exception e)
{
Console.Error.WriteLine(e);
}
}
Console.WriteLine("Resuming Resharper");
dte.ExecuteCommand("ReSharper_Resume");
try
{
dte.Quit();
}
catch (Exception e)
{
Console.Error.WriteLine(e);
}

Related

SolutionEvents for Visual studio 2010 addin does not fire

I'm building an visual studio 2010 addin and trying to hook into an event when the solution is loaded.
Basically what I have found is that SolutionEvents.Opened seems to be what I'm looking for, however listening to it in OnConnection does not seem to be working:
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
applicationObject = (DTE2)application;
var outputWindow = (OutputWindow)applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object;
outputWindowPane = outputWindow.OutputWindowPanes.Add("My Pane");
applicationObject.Events.SolutionEvents.Opened += SolutionEventsOnOpened;
outputWindowPane.OutputString("Connected");
}
private void SolutionEventsOnOpened()
{
outputWindowPane.OutputString("SolutionEventsOnOpened");
}
The only thing outputed is "Connected".
I have tried to listen to SolutionItemsEvents.ItemAdded and SolutionEvents.ProjectAdded and also they do not fire.
Should I init the events elsewhere? (Note I have R# installed, perhaps it is knowed to cause issues?)
Found the solution here: http://blogs.microsoft.co.il/blogs/kolbis/archive/2007/11/22/hooking-up-to-the-solution-events.aspx
Basically, you need to declare members at your add-in class scope for the SolutionEvents and Events variables, and assign them, and then reference the eventhandlers through that. E.g.
private Events2 m_events;
private SolutionEvents m_solutionEvents;
then in the OnConnection handler (when your plugin gets initialised) do this:
m_application = Application as DTE2;
m_events = (Events2)m_application.Events;
m_solutionEvents = m_events.SolutionEvents;
and finally, wire up the solution Opened/AfterClosing events, as follows:
m_solutionEvents.Opened += m_openSolution;
m_solutionEvents.AfterClosing += m_closeSolution;
Then the events will fire.
I presume the reason for doing this is because otherwise the Events/SolutionEvents objects get changed or GC'd (or both ;-).
HTH
With VS2010, when opening a .sln file that leads to start a new VS2010 instance, it is worth noting that SolutionEvents.Opened is fired before EventsObj.OnStartupComplete is fired. So if you register SolutionEvents.Opened during EventsObj.OnStartupComplete it won't fire in this situation.
As far as I know all VS versions post-2010 [2012-2019] fire SolutionEvents.Opened after EventsObj.OnStartupComplete is fired.

Copy object values in Visual Studio debug mode

In Visual Studio debug mode it's possible to hover over variables to show their value and then right-click to "Copy", "Copy Expression" or "Copy Value".
In case the variable is an object and not just a basic type, there's a + sign to expand and explore the object. It there a way to copy all that into the clipboard?
In the immediate window, type
?name_of_variable
This will print out everything, and you can manually copy that anywhere you want, or use the immediate window's logging features to automatically write it to a file.
UPDATE: I assume you were asking how to copy/paste the nested structure of the values so that you could either search it textually, or so that you can save it on the side and then later compare the object's state to it. If I'm right, you might want to check out the commercial extension to Visual Studio that I created, called OzCode, which lets you do these thing much more easily through the "Search" and "Compare" features.
UPDATE 2 To answer #ppumkin's question, our new EAP has a new Export feature allows users to Export the variable values to Json, XML, Excel, or C# code.
Full disclosure: I'm the co-creator of the tool I described here.
You can run below code in immediate window and it will export to an xml file the serialized XML representation of an object:
(new System.Xml.Serialization.XmlSerializer(obj.GetType())).Serialize(new System.IO.StreamWriter(#"c:\temp\text.xml"), obj)
Source: Visual Studio how to serialize object from debugger
Most popular answer from https://stackoverflow.com/a/23362097/2680660:
With any luck you have Json.Net in you appdomain already. In which
case pop this into your Immediate window:
Newtonsoft.Json.JsonConvert.SerializeObject(someVariable)
Edit: With .NET Core 3.0, the following works too:
System.Text.Json.JsonSerializer.Serialize(someVariable)
There is a extension called Object Exporter that does this conveniently.
http://www.omarelabd.net/exporting-objects-from-the-visual-studio-debugger/
Extension: https://visualstudiogallery.msdn.microsoft.com/c6a21c68-f815-4895-999f-cd0885d8774f
You can add a watch for that object, and in the watch window, expand and select everything you want to copy and then copy it.
By using attributes to decorate your classes and methods you can have a specific value from your object display during debugging with the DebuggerDisplay attribute e.g.
[DebuggerDisplay("Person - {Name} is {Age} years old")]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
I always use:
string myJsonString = JsonConvert.SerializeObject(<some object>);
Then I copy the string value which unfortunately also copies the back slashes.
To remove the backlashes go here:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_replace
Then within the <p id="demo">Visit Microsoft!</p> element replace the text with the text you copied.
then replace the var res = str.replace("Microsoft", "W3Schools"); line with
var res = str.replace(/\\/g, '')
Run these new changes but don't forget to click the "try it" button on the right.
Now you should have all the text of the object in json format that you can drop in a json formatter like http://jsonformatter.org or to create a POCO you can now use http://json2csharp.com/
ObjectDumper.NET
This is an awesome way!
You probably need this data for a unit test, so create a Sandbox.cs temporary test or you can create a Console App.
Make sure to get NuGet package, ObjectDumper.NET, not ObjectDumper.
Run this test (or console app)
View test output or text file to get the C# initializer code!
Code:
[TestClass]
public class Sandbox
{
[TestMethod]
public void GetInitializerCode()
{
var db = TestServices.GetDbContext();
var list = db.MyObjects.ToList();
var literal = ObjectDumper.Dump(list, new DumpOptions
{
DumpStyle = DumpStyle.CSharp,
IndentSize = 4
});
Console.WriteLine(literal); // Some test runners will truncate this, so use the file in that case.
File.WriteAllText(#"C:\temp\dump.txt", literal);
}
}
I used to use Object Exporter, but it is 5 years old and no longer supported in Visual Studio. It seems like Visual Studio Extensions come and go, but let's hope this NuGet package is here to stay! (Also it is actively maintained as of this writing.)
Google led me to this 8-year-old question and I ended up using ObjectDumper to achieve something very similar to copy-pasting debugger data. It was a breeze.
I know the question asked specifically about information from the debugger, but ObjectDumper gives information that is basically the same. I'm assuming those who google this question are like me and just need the data for debugging purposes and don't care whether it technically comes from the debugger or not.
I know I'm a bit late to the party, but I wrote a JSON implementation for serializing an object, if you prefer to have JSON output. Uses Newtonsoft.Json reference.
private static void WriteDebugJSON (dynamic obj, string filePath)
{
using (StreamWriter d = new StreamWriter(filePath))
{
d.Write(JsonConvert.SerializeObject(obj));
}
}
I've just right clicked on the variable and selected AddWatch, that's bring up watch window that consists of all the values. I selected all and paste it in a text a text editor, that's all.
Object Dumper is a free and open source extension for Visual Studio and Visual Studio Code.
"Dump as" commands are available via context menu in the Code and Immediate windows.
It's exporting objects to:
C# object initialization code,
JSON,
Visual Basic object initialization code,
XML,
YAML.
I believe that combined with the Diff tool it can be helpful.
I'm the author of this tool.
if you have a list and you want to find a specific variable:
In the immediate window, type
myList.Any(s => s.ID == 5062);
if this returns true
var myDebugVar = myList.FirstOrDefault(s => s.ID == 5062);
?myDebugVar
useful tips here, I'll add my preference for when i next end up here asking this question again in the future.
if you don't mind adding an extension that doesn't require output files or such there's the Hex Visualizer extension for visual studio, by mladen mihajlovic, he's done versions since 2015.
provides a nice display of the array via the usual magnifine glass view object from the local variables window.
https://marketplace.visualstudio.com/items?itemName=Mika76.HexVisualizer2019 is the 2019 version.
If you're in debug mode, you can copy any variable by writing copy() in the debug terminal.
This works with nested objects and also removes truncation and copies the complete value.
Tip: you can right click a variable, and click Copy as Expression and then paste that in the copy-function.
System.IO.File.WriteAllText("b.json", page.DebugInfo().ToJson())
Works great to avoid to deal with string debug format " for quote.
As #OmerRaviv says, you can go to Debug → Windows → Immediate where you can type:
myVariable
(as #bombek pointed out in the comments you don't need the question mark) although as some have found this limits to 100 lines.
I found a better way was to right click the variable → Add Watch, then press the + for anything I wanted to expand, then used #GeneWhitaker's solution, which is Ctrl+A, then copy Ctrl+C and paste into a text editor Ctrl+V.

Visual Studio 2008 Add-In Check if Hierarchy Item is solution folder

I've got a visual studio addin written by developer who is no longer at the company and have no idea how to debug it. But I want to add a feature so it can recurse into solution folders.
Sounds simple but I'm not sure the api allows testing for this?
Well there's got to be a way because AnkhSVN and VisualSVN work fine with Solution Folders.
StackOverflow I'm reaching out for some help on this issue.
Thanks
Notes
-We are using solution folders to hide "Dependency Projects" which are basically a list of project references that we probably don't care about in the particular solution and want to hide by default.
public class Connect : IDTExtensibility2, IDTCommandTarget
{
public void GetProjectLocations(DTE2 dte)
{
UIHierarchy UIH = dte.ToolWindows.SolutionExplorer;
try
{
UIHierarchyItem UIHItemd = UIH.UIHierarchyItems.Item(1);
}
catch (Exception E)
{
Debug.Write(E);
}
UIHierarchyItem UIHItem = UIH.UIHierarchyItems.Item(1);//this looks suspect to me
// Iterate through first level nodes.
for (int i = 1; i <= UIHItem.UIHierarchyItems.Count; i++)
{
Project TempGeneralProjObj = dte.Solution.Item(i);
if (TempGeneralProjObj.Kind == PrjKind.prjKindCSharpProject)
{
}
}
}
}
So far from my tests it appears that solution folders will cast to type Project surprisingly and once that is done the Project.ProjectItems property will hold a list of Projects that may exists underneath that folder. So in short, this is one way to at least get information about how things are structured. The problem however is that each ProjectItem located underneath a solution folder appears to cast find to type ProjectItem but doesn't seem to be able to be cast to a Project.
This is how I'm currently detecting a solution folder in my loop.
if(project.Kind == "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}")
{
// TODO: Do your thing
}
This has also been frustrating me and I've also noticed a bug in how ActiveReports handles solution folders as well which is related to this same issue.
UPDATE!
Ok so I found the solution but I can't claim it 100% because I found most of it at Macaw's Blog.
So it appears that my original findings were right on however in order to get the actual project type for each ProjectItem under the solution item you need to look under the ProjectItem.SubProject property.
Now Macaw takes a recursive approach to walking the project structure which I think I would also normally recommend however in my case I wanted a single method implementation to simply log out an XML representation of the project for simple research purposes so I ended up using a Stack implementation. For reference you can find my code below which is successfully handling at least one level of solution folders full of projects only and no other specialty solution items.
XElement rootNode = new XElement("Solution");
rootNode.Add(new XAttribute("Name", _applicationObject.Solution.FullName));
Stack<Project> projectStack =
new Stack<Project>(_applicationObject.Solution.Projects.Cast<Project>());
while(projectStack.Count > 0)
{
var project = (Project)projectStack.Pop();
var solutionItemName = "Project";
if(project.Kind == "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}")
{
foreach(ProjectItem innerProject in project.ProjectItems)
{
if(innerProject.SubProject != null)
{
projectStack.Push(innerProject.SubProject);
}
}
solutionItemName = "Folder";
}
var projectNode = new XElement(
solutionItemName,
new XAttribute("Name", project.Name),
new XAttribute("Kind", project.Kind)
);
rootNode.Add(projectNode);
foreach(ProjectItem item in project.ProjectItems)
{
var itemNode = new XElement("Item", new XAttribute("Name", item.Name));
projectNode.Add(itemNode);
if(item.Properties == null)
{
continue;
}
foreach(Property property in item.Properties)
{
var propertyNode = new XElement(property.Name, property.Value);
itemNode.Add(propertyNode);
}
}
}
By the fact of this post and by apparent bugs in other Add-ins it is apparent that this isn't the most intuitive design but thats what we have to live with.
To debug a Visual Studio add-in, load the source code into a copy of visual studio that is not running the add-in. Then, configure the project to start a second copy of visual studio when you "run" the project, that second copy will then run with the first able to breakpoint and debug it.
Make sure you have a batch file (or equivalent) to clean up, so that you can always get back to running VS without the plugin.
Useful resources ...
How to debug a Visual Studio .NET 2005 Add-In
Walkthrough: Debugging an Add-in Project

Break when a value changes using the Visual Studio debugger

Is there a way to place a watch on variable and only have Visual Studio break when that value changes?
It would make it so much easier to find tricky state issues.
Can this be done?
Breakpoint conditions still need a breakpoint set, and I'd rather set a watch and let Visual Studio set the breakpoints at state changes.
In the Visual Studio 2005 menu:
Debug -> New Breakpoint -> New Data Breakpoint
Enter:
&myVariable
You can also choose to break explicitly in code:
// Assuming C#
if (condition)
{
System.Diagnostics.Debugger.Break();
}
From MSDN:
Debugger.Break:
If no debugger is attached, users are
asked if they want to attach a
debugger. If yes, the debugger is
started. If a debugger is attached,
the debugger is signaled with a user
breakpoint event, and the debugger
suspends execution of the process just
as if a debugger breakpoint had been
hit.
This is only a fallback, though. Setting a conditional breakpoint in Visual Studio, as described in other comments, is a better choice.
In Visual Studio 2015, you can place a breakpoint on the set accessor of an Auto-Implemented Property and the debugger will break when the property is updated
public bool IsUpdated
{
get;
set; //set breakpoint on this line
}
Update
Alternatively; #AbdulRaufMujahid has pointed out in the comments that if the auto implemented property is on a single line, you can position your cursor at the get; or set; and hit F9 and a breakpoint will be placed accordingly. Nice!
public bool IsUpdated { get; set; }
Imagine you have a class called A with the following declaration.
class A
{
public:
A();
private:
int m_value;
};
You want the program to stop when someone modifies the value of "m_value".
Go to the class definition and put a breakpoint in the constructor of A.
A::A()
{
... // set breakpoint here
}
Once we stopped the program:
Debug -> New Breakpoint -> New Data Breakpoint ...
Address: &(this->m_value)
Byte Count: 4 (Because int has 4 bytes)
Now, we can resume the program. The debugger will stop when the value is changed.
You can do the same with inherited classes or compound classes.
class B
{
private:
A m_a;
};
Address: &(this->m_a.m_value)
If you don't know the number of bytes of the variable you want to inspect, you can use the sizeof operator.
For example:
// to know the size of the word processor,
// if you want to inspect a pointer.
int wordTam = sizeof (void* );
If you look at the "Call stack" you can see the function that changed the value of the variable.
Change the variable into a property and add a breakpoint in the set method. Example:
private bool m_Var = false;
protected bool var
{
get {
return m_var;
}
set {
m_var = value;
}
}
Update in 2019:
This is now officially supported in Visual Studio 2019 Preview 2 for .Net Core 3.0 or higher. Of course, you may have to put some thoughts in potential risks of using a Preview version of IDE. I imagine in the near future this will be included in the official Visual Studio.
https://blogs.msdn.microsoft.com/visualstudio/2019/02/12/break-when-value-changes-data-breakpoints-for-net-core-in-visual-studio-2019/
Fortunately, data breakpoints are no longer a C++ exclusive because they are now available for .NET Core (3.0 or higher) in Visual Studio 2019 Preview 2!
If you are using WPF, there is an awesome tool : WPF Inspector.
It attaches itself to a WPF app and display the full tree of controls with the all properties, an it allows you (amongst other things) to break on any property change.
But sadly I didn't find any tool that would allow you to do the same with ANY property or variable.
I remember the way you described it using Visual Basic 6.0. In Visual Studio, the only way I have found so far is by specifying a breakpoint condition.
Right click on the breakpoint works fine for me (though mostly I am using it for conditional breakpoints on specific variable values. Even breaking on expressions involving a thread name works which is very useful if you're trying to spot threading issues).
As Peter Mortensen wrote:
In the Visual Studio 2005 menu:
Debug -> New Breakpoint -> New Data Breakpoint
Enter: &myVariable
Additional information:
Obviously, the system must know which address in memory to watch.
So
- set a normal breakpoint to the initialisation of myVariable (or myClass.m_Variable)
- run the system and wait till it stops at that breakpoint.
- Now the Menu entry is enabled, and you can watch the variable by entering &myVariable,
or the instance by entering &myClass.m_Variable. Now the addresses are well defined.
Sorry when I did things wrong by explaining an already given solution. But I could not add a comment, and there has been some comments regarding this.
You can use a memory watchpoint in unmanaged code. Not sure if these are available in managed code though.
You can probably make a clever use of the DebugBreak() function.
You can optionally overload the = operator for the variable and can put the breakpoint inside the overloaded function on specific condition.

Is there a way to specify outlining defaults in Visual Studio 2008 so that a file opens up with members collapsed by default?

What I would like to do is have VS2008, when I open a code file, collapse all members of the classes/interfaces in the file by default (including, crucially, any XML documentation and comments).
I do not want to use regions, at all.
I would also like to be able to use the ctrl+m, ctrl+l chord to toggle all member outlining (for example, if everything is collapsed, I would like it to expand all of the members, but not the comments or XML documentation).
Possible? How?
Yes to part 1.
Unsure about part 2.
To have VS2008 automatically open files in a Collapsed state you'll need to create an addin to run the "Edit.CollapsetoDefinition" when each document opens.
This isn't overly tricky - The difficult parts seems to be the that you have to run the code a few milliseconds after the document is actually opened so you need to use the threed pool to do that.
Create an Addin project for VS2008.
Add this code (see following) to the end of the OnConnection Method of the Connect class.
switch (connectMode)
{
case ext_ConnectMode.ext_cm_UISetup:
case ext_ConnectMode.ext_cm_Startup:
//Do nothing OnStartup will be called once IDE is initialised.
break;
case ext_ConnectMode.ext_cm_AfterStartup:
//The addin was started post startup so we need to call its initialisation manually
InitialiseHandlers();
break;
}
Add this method to the Connect class
private void InitialiseHandlers()
{
this._openHandler = new OnOpenHandler(_applicationObject);
}
Add a call to InitialiseHandlers() to the OnStartupComplete method of the Connect class.
public void OnStartupComplete(ref Array custom)
{
InitialiseHandlers();
}
Add this class to the project.
using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE80;
using EnvDTE;
using System.Threading;
namespace Collapser
{
internal class OnOpenHandler
{
DTE2 _application = null;
EnvDTE.Events events = null;
EnvDTE.DocumentEvents docEvents = null;
internal OnOpenHandler(DTE2 application)
{
_application = application;
events = _application.Events;
docEvents = events.get_DocumentEvents(null);
docEvents.DocumentOpened +=new _dispDocumentEvents_DocumentOpenedEventHandler(OnOpenHandler_DocumentOpened);
}
void OnOpenHandler_DocumentOpened(EnvDTE.Document document)
{
if (_application.Debugger.CurrentMode != dbgDebugMode.dbgBreakMode)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(Collapse));
}
}
private void Collapse(object o)
{
System.Threading.Thread.Sleep(150);
_application.ExecuteCommand("Edit.CollapsetoDefinitions", "");
}
}
}
And now all opened files should be fully collapsed.
It would be much easier to use the Visual Studio Macros to do the same thing. Editing the "EnvironmentEvents" Macro file in MyMacros and adding a handler for DocumentEvents.DocumentOpened with :
DTE.ExecuteCommand("Edit.CollapsetoDefinitions")
A quick way to collapse all outlining to function-definitions is to press:
Contextmenu-button*(next to your right windows button)*, L, O
I use it all the time. If there is a real hotkey for this please tell me :)
I had tried working out some Visual Basic code for a macro myself, borrowing from different places, and couldn't get anything to work. So what did I do? Why, I asked a question on StackOverflow of course! It got answered, I added the suggested code to my EnvironmentEvents macro, and now when I open CS files, after about a second, all my definitions are collapsed. :)

Resources