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

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

Related

Coded UI error: The following element is not longer availabe

I recorded some test cases with CUIT in VS2010. Everything worked fine the day before. So, today I run again, all the test failed, with the warning: The following element is no longer available ... and I got the exception : Can't perform "Click" on the hidden control, which is not true because all the controls are not hidden. I tried on the other machine, and they failed as well.
Does anyone know why it happens? Is it because of the web application for something else? Please help, thanks.
PS: So I tried to record a new test with the same controls that said "hidden controls", and the new test worked!? I don't understand why.
EDIT
The warning "The following element blah blah ..." appears when I tried to capture an element or a control while recording. The source code of the button is said 'hidden'
public HtmlImage UIAbmeldenImage
{
get
{
if ((this.mUIAbmeldenImage == null))
{
this.mUIAbmeldenImage = new HtmlImage(this);
#region Search Criteria
this.mUIAbmeldenImage.SearchProperties[HtmlImage.PropertyNames.Id] = null;
this.mUIAbmeldenImage.SearchProperties[HtmlImage.PropertyNames.Name] = null;
this.mUIAbmeldenImage.SearchProperties[HtmlImage.PropertyNames.Alt] = "abmelden";
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.AbsolutePath] = "/webakte-vnext/content/apps/Ordner/images/logOut.png";
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.Src] = "http://localhost/webakte-vnext/content/apps/Ordner/images/logOut.png";
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.LinkAbsolutePath] = "/webakte-vnext/e.consult.9999/webakte/logout/index";
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.Href] = "http://localhost/webakte-vnext/e.consult.9999/webakte/logout/index";
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.Class] = null;
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.ControlDefinition] = "alt=\"abmelden\" src=\"http://localhost/web";
this.mUIAbmeldenImage.FilterProperties[HtmlImage.PropertyNames.TagInstance] = "1";
this.mUIAbmeldenImage.WindowTitles.Add("Akte - Test Akte Coded UI VS2010");
#endregion
}
return this.mUIAbmeldenImage;
}
}
Although I am running Visual Studio 2012, I find it odd that we started experiencing the same problem on the same day, I can not see any difference in the DOM for the Coded UI Tests I have for my web page, but for some reason VS is saying the control is hidden and specifies the correct ID of the element it is looking for (I verified that the ID is still the same one). I even tried to re-record the action, because I assumed that something must have changed, but I get the same error.
Since this sounds like the same problem, occurring at the same time I am thinking this might be related to some automatic update? That's my best guess at the moment, I am going to look into it, I will update my post if I figure anything out.
EDIT
I removed update KB2870699, which removes some voulnerability in IE, this fixed the problems I was having with my tests. This update was added on the 12. september, so it fits. Hope this helps you. :)
https://connect.microsoft.com/VisualStudio/feedback/details/800953/security-update-kb2870699-for-ie-breaks-existing-coded-ui-tests#tabs
Official link to get around the problem :
http://blogs.msdn.com/b/visualstudioalm/archive/2013/09/17/coded-ui-mtm-issues-on-internet-explorer-with-kb2870699.aspx
The problem is more serious than that! In my case I can't even record new Coded UI Tests. After I click in any Hyper Link of any web page of my application the coded UI test builder cannot record that click "The following element is no longer available....".
Apparently removing the updates, as said by AdrianHHH do the trick!
Shut down VS2010, launch it again "Run as administrator".
There may be a field in the SearchProperties (or possible the FilterProperties) that has a value set by the web site, or that represents some kind of window ID on your desktop. Another possibility is that the web page title changes from day to day or visit to visit. Different executions of the browser or different visits to the web page(s) create different values. Removing these values from the SearchProperties (or FilterProperties) or changing the check for the title from an equals to a contains for a constant part of the title should fix the problem. Coded UI often searches for more values than the minimum set needed.
Compare the search properties etc for the same control in the two recorded tests.
Update based extra detail given in the comments:
I solved a similar problem as follows. I copied property code similar to that shown in your question into a method that called FindMatchingControls. I checked how many controls were returned, in my case up to 3. I examined various properties of the controls found, by writing lots of text to a debug file. In my case I found that the Left and Top properties were negative for the unwanted, ie hidden, controls.
For your code rather than just using the UIAbmeldenImage property, you might call the method below. Change an expression such as
HtmlImage im = UIMap.abc.def.UIAbmeldenImage;
to be
HtmlImage im = FindHtmlHyperLink(UIMap.abc.def);
Where the method is:
public HtmlImage FindHtmlHyperLink(HtmlDocument doc)
{
HtmlImage myImage = new HtmlImage(doc);
myImage.SearchProperties[HtmlImage.PropertyNames.Id] = null;
myImage.SearchProperties[HtmlImage.PropertyNames.Name] = null;
myImage.SearchProperties[HtmlImage.PropertyNames.Alt] = "abmelden";
myImage.FilterProperties[HtmlImage.PropertyNames.AbsolutePath] = "/webakte-vnext/content/apps/Ordner/images/logOut.png";
myImage.FilterProperties[HtmlImage.PropertyNames.Src] = "http://localhost/webakte-vnext/content/apps/Ordner/images/logOut.png";
myImage.FilterProperties[HtmlImage.PropertyNames.LinkAbsolutePath] = "/webakte-vnext/e.consult.9999/webakte/logout/index";
myImage.FilterProperties[HtmlImage.PropertyNames.Href] = "http://localhost/webakte-vnext/e.consult.9999/webakte/logout/index";
myImage.FilterProperties[HtmlImage.PropertyNames.Class] = null;
myImage.FilterProperties[HtmlImage.PropertyNames.ControlDefinition] = "alt=\"abmelden\" src=\"http://localhost/web";
myImage.FilterProperties[HtmlImage.PropertyNames.TagInstance] = "1";
myImage.WindowTitles.Add("Akte - Test Akte Coded UI VS2010");
UITestControlCollection controls = myImage.FindMatchingControls();
if (controls.Count > 1)
{
foreach (UITestControl con in controls)
{
if ( con.Left < 0 || con.Top < 0 )
{
// Not on display, ignore it.
}
else
{
// Select this one and break out of the loop.
myImage = con as HtmlImage;
break;
}
}
}
return myImage;
}
Note that the above code has not been compiled or tested, it should be taken as ideas not as the final code.
I had the same problem on VS 2012. As a workaround, you can remove that step, and re-record it again. That usually works.
One of the biggest problem while analyzing the Coded UI test failures is that the error stack trace indicates the line of code which might be completely unrelated to the actual cause of failure.
I would suggest you to enable HTML logging in your tests - this will display step by step details of how Coded UI tried to execute the tests - with screenshots of your application. It will also highlight the control in red which Coded UI is trying to search/operate upon.This is very beneficial in troubleshooting the actual cause of test failures.
To enable tracing you can just add the below code to your app.config file --

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

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);
}

Create a solution and add a project using "VisualStudio.DTE.10.0"

I'm trying to create a VS2010 solution and add a project from a stand-alone app (not an add-in). I can create an instance of VS2010, but I'm not able to determine how to create a project properly...I can only find an example of how to create a project using the EnvDTE80 object, which later causes an exception because the project file is in an earlier format and needs to be upgraded. I have this:
EnvDTE80.DTE2 dte2;
object obj;
System.Type t;
t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0", true);
obj = System.Activator.CreateInstance(t, true);
dte2 = (EnvDTE80.DTE2)obj;
What I'm looking for is the equivalent of something like "EnvDTE100.DTE2" but don't know how to get there.
Thanks
You do not have to go via DTE object. The treatment to the object solution4 it's different you should do this
Type latestSolution = Type.GetTypeFromProgID("VisualStudio.10.0", true);
EnvDTE100.Solution4 vsSolution = (EnvDTE100.Solution4)Activator.CreateInstance(latestSolution, true);
I think I'm doing something similar, I have a application that creates a solution and loads two projects from templates that I created in VS2010. You're right in that it seems everything still uses the EnvDTE80, even in VS2010, but then we use it to create a 2010 solution:
System.Type type = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
Object obj = System.Activator.CreateInstance(type, true);
EnvDTE80.DTE2 dte2 = (EnvDTE80.DTE2)obj;
EnvDTE100.Solution4 soln = (EnvDTE100.Solution4)dte2.Solution;
Then you can call methods on the soln object to create your project (in my case its AddFromTemplate).

Convert a Visual Studio resource file to a text file?

I know there are tools to get text files to resource files for Visual Studio. But I want to get the text from my resource files to a text file so they can be translated. Or is there a better way to do this?
You could use Resx Editor, a small translation-oriented file editor.
Target audience: translators.
Supported file format: Microsoft RESX 2.0
Here is a link to Joannès Vermoel's (the author of the free tool) weblog entry about it.
In the end I just used a quick hack:
public class Export
{
public string Run()
{
var resources = new StringBuilder();
var assembly = Assembly.GetExecutingAssembly();
var types = from t in assembly.GetTypes()
where t != typeof(Export)
select t;
foreach (Type t in types)
{
resources.AppendLine(t.Name);
resources.AppendLine("Key, Value");
var props = from p in t.GetProperties()
where !p.CanWrite && p.Name != "ResourceManager"
select p;
foreach (PropertyInfo p in props)
{
resources.AppendFormat("\"{0}\",\"{1}\"\n", p.Name, p.GetValue(null));
}
resources.AppendLine();
}
return resources.ToString();
}
}
Add this code to the project which contains your.resx files (mine are in a separate "Languages" project) then use the following code to save the result into a .csv so that it can be loaded with a spreadsheet editor.
var hack = new Languages.Export();
var resourcesSummary = hack.Run();
var cultureName = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
using (TextWriter file = File.CreateText(#"C:\resources." + cultureName + ".csv"))
{
file.Write(resourcesSummary);
}
This does not allow you to import files from the .csv back to your .resx files so that they can be compiled. It would be nice to have a utility that would do that.
You can use Simple Resx Editor, it has some interesting features that will help you into the translation process.
Even though it is counter intuitive, it's a better idea to translate the exe rather than the resource file. Read why here:
http://www.apptranslator.com/misconceptions.html
You may want to have a look at Excel Resource Transfer. It is
an Add-In for Microsoft Excel to import and export texts from resource files.
There is a trial version. The full version costs 25,- Euro.
If you're doing this for a web project, a better way to do internationalization (including translation) is to use the i18n nuget package. Not only does work better with templates but it has other nice-to-haves like localized URLs.
Here's an example from the github repo:
<div id="content">
<h2>[[[Welcome to my web app!]]]</h2>
<h3><span>[[[Amazing slogan here]]]</span></h3>
<p>[[[Ad copy that would make Hiten Shah fall off his chair!]]]</p>
<span class="button" title="[[[Click to see plans and pricing]]]">
<a href="#Url.Action("Plans", "Home", new { area = "" })">
<strong>[[[SEE PLANS & PRICING]]]</strong>
<span>[[[Free unicorn with all plans!]]]</span>
</a>
</span>
</div>
Running a post-build task generates a PO database that can be provided to translators that use PO editing tools (like POEdit) to provide locale-specific text.
You could use winres.exe from Microsoft, it lets you localize windows forms without having to use Visual Studio. It doesn't save the resources to a text file, but the idea is that the localization expert for each culture could use the tool to generate a localized versions of the application.
Here's a better explanation:
http://msdn.microsoft.com/en-us/library/8bxdx003(VS.80).aspx

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