Is it possible to search inside an object for values and/or other field while debugging a C# application?
I'm looking for a deep search that can drill down the object for many levels.
What I'm looking for is a way to search (like F3 for documents search) inside very complex objects (while debugging, in the Quick watch window for example).
You could use OzCode (an add-on for Visual Studio), which lets you search for the members you want to see from within the on-hover-DataTip or the QuickWatch window.
See example in the following screenshot:
Full disclosure: I am the co-creator of "OzCode".
If you want to do whitout an add-on it can be done by going to the object list, selecting all objects (ctrl+a) and copy them to a searchable text-editor. This will give you a newline seperated list.
I think there is no built-in feature to lets you, dive in deep in the objects in debugging mode, Unless use extensions if available.
Besides Wilson Kao's post, you can also try the simplest approach that I use:
Put a breakpoint at a place where a variable referencing the object will be used.
Hover mouse over the variable when the breakpoint is hit. You should see a popup showing the top level properties of the object.
Use the little + buttons on the left to go deeper into the object. It could get confusing.
You can also pin certain properties that you find deep down so you don't have to look for them again and again (pin button appears on the right side of each property when you hover over the property)
Here's an exmaple of what it looks like (the variable is books):
Source: http://blogesh.wordpress.com/2008/09/09/visual-studio-debugging-tips-and-tricks/
Edit: There is a way to get all the properties and their values that you access through the manual hover-and-click method (ie in the above image, you can get ISBN and its value through code). However you have to use Visual Basic code. You can then do a search on the results for a specific value.
First, you need to go read up on Tracepoints and custom Macros:
Click and go to "TracePoints – Running a Custom Macro"
Also, here
Next you need to make a Macro to do what you want.
In Visual Studio, go to Tools -> Macros -> Macros IDE...
Add a new Macro. There should be a preset blank one called Module 1. In here, you add routines to do what you want. The following is a Macro I made that will go through a certain variable and output the properties of it (basically, output the data you get in the cover-and-click method). This outputs to the Output window, which you can open through View -> Output.
Sub DisplayAllProperties()
Dim outputWindow As EnvDTE.OutputWindow
outputWindow = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput).Object
Dim currentStackFrame As EnvDTE.StackFrame
currentStackFrame = DTE.Debugger.CurrentStackFrame
outputWindow.ActivePane.OutputString("*Dumping Local Variables*" + vbCrLf)
For Each exp As EnvDTE.Expression In currentStackFrame.Locals
If (exp.Name = "this") Then ' Here, I am only searching in a variable named "this"
outputWindow.ActivePane.OutputString("- " + exp.Name + ": " + exp.Value.ToString() + vbCrLf)
helperDisplay(exp.DataMembers, outputWindow, 1)
End If
Next
End Sub
Private Sub helperDisplay(ByRef exps As EnvDTE.Expressions, ByRef OutputWindow As EnvDTE.OutputWindow, ByVal n As Integer)
For Each ex In exps
helperTabs(n, OutputWindow)
If (ex.Name = "Non-Public members" Or ex.Name = "Static members") Then
OutputWindow.ActivePane.OutputString("~ " + ex.Name + ": There are " + ex.DataMembers.Count.ToString + vbCrLf)
Else
OutputWindow.ActivePane.OutputString("~ " + ex.Name + ": " + ex.Value.ToString() + vbCrLf)
If (ex.DataMembers.Count <> 0) Then
helperDisplay(ex.DataMembers, OutputWindow, n + 1)
End If
End If
Next
End Sub
Private Sub helperTabs(ByVal n As Integer, ByRef OutputWindow As EnvDTE.OutputWindow)
For i = 1 To n Step 1
OutputWindow.ActivePane.OutputString(vbTab)
Next
End Sub
This code is giving me exceptions for some DevExpress controls I tested it on. I think it's because some values can't be accessed. I have never coded in VB before so there are probably bugs in there...Play with it and see if it can do what you want (ie output only the properties that match what you need). The good part is, you can change the Macro code AS you are debugging, so no need to stop your project while you edit the Macro!
To use the Macro, you need to put a breakpoint somewhere in your code that will be hit, and will be able to access the object you want.
-> Right click the breakpoint and go to When Hit... Check off Run a macro: and select your Macro from the dropdown.
When you are in debug mode, go up to Debug on the menu bar, and go to the drop down menu of windows. There, you will see locals. This will tell you what values your variables are at your current breakpoints. You can also dive deep down into all of your objects as well through a tree menu. To look for a particular object, you can watch, and then input the variable you want to watch there. Make sure you have the breakpoints in the right place. Good luck!
Related
Original Question
I have this expandable folder UIObject that I need to be able to expand to show all the subfolders. It can not be double clicked as this does not expand the folders. I saw from this documentation, https://admhelp.microfocus.com/leanft/en/14.02/NetSDKReference/HP.LFT.SDK~HP.LFT.SDK.Java.ITreeView.html as well as some others that there is a concept of an ITreeView and an ITreeViewNode.
How can I expand this element? I really just need some examples in code of how we can take an object, defeine it as a ITreeView and ITreeView node and expand it.
Result
Even though it is not the best solution, it is possible to do this using the Workaround suggested below and this is the method that made it happen
public void ExpandFolder(int index)
{
IUiObject folder = ViewPage.FolderExplorer.Describe<IUiObject>(new UiObjectDescription
{
ObjectName = "TreeViewItem",
Index = (uint)index
});
var expandButton = folder.AbsoluteLocation;
expandButton.X = expandButton.X + 2;
expandButton.Y = expandButton.Y + 4;
Mouse.Click(expandButton);
GeneralUtilities.Sleep(1);
}
In this case, there was a small drop down arrow to the left of the element. I couldn't identify that, so I identified the folder and manipulated the click. If anyone stumbles upon this and knows a more direct way to do this using LeanFT I would very much like to see an example. If not, and you are here trying to find help - I hope this helps you!
The theory
In order to Expand and Collapse a Java ITreeView, these are the steps:
Describe the ITreeView:
ITreeView treeView = Desktop.Describe<IWindow>(new WindowDescription())
.Describe<ITreeView>(new TreeViewDescription()
{
AttachedText = "Etc"
});
Get one of it's nodes:
ITreeViewNode treeViewNode = treeView.GetNode("someNode");
Expand or collapse it:
treeViewNode.Expand(); treeViewNode.Collapse();
The only expandable object is the ITreeViewNode (that is, this is the one that has the .Expand method), and the only way to get to the node is via an ITreeView, as shown above.
In practice...
You want to take an UIObject (I suspect this is what object identification center identified, right?) as an ITreeView, so that you can call Expand and Collapse on it?
This is not possible.
In these SDKs, every description is a generic element. In Java it's a UIObject, in Web it's a WebElement, etc..
Those more unique, like a tree view, extend the generic one (UIObject) and adds one more identification property in the process
In the ITreeView case, most probably it's the UIObject with NativeClass set as "javax.swing.JTree"
If Object Identification Center didn't identify the expandable object as an ITreeView, it's because it isn't.
Workaround
If your goal is just to expand, and manually double clicking works, then you can:
Identify the UIObject;
Calculate the coordinates of the point you manually double click, relative to the upper left pixel of the UIObject. (E.G. 5 pixels down, 5 to the right)
You can approximate it, go for a try and error, or use tools that can help.
Use HP.LFT.SDK.Mouse class to double click that exact location:
var loc = theUiButton.AbsoluteLocation;
var p = new System.Drawing.Point(loc.X + 5, loc.Y + 5);
Mouse.DoubleClick(p, MouseButton.Left);
The reason why it doesn't work right now is because .DoubleClick, by default, performs double click in the center of the UIObject, and I have a hunch that's not where the expandable object is - so you need to provide fine tuning parameters.
Every so often, I find the need to debug this type of code:
function DoSomething(int parm1)
{
return SomeClass.SomeMethod(parm1);
}
In other words, I need to see the return value of SomeClass.SomeMethod(parm1);
The only way I know of currently to do this is to rewrite the code like this:
function DoSomething(int parm1)
{
var returnValue = SomeClass.SomeMethod(parm1);
return returnValue;
}
Then I can put a break point on the second line and inspect the value of returnValue.
Is there a way to inspect this value without rewriting the code?
You can use the Autos debug window (Ctrl + D, A). It will show the result of the called function. See the image -> 'ConsoleApp2.Program.Return returned' is the result of the function.
NOTE: This will show the result once you've step out of the function. So not exactly what you need, but it can be useful in chained calls where several functions are called this way.
Go to Quick Watch window
You can use the Watch (Debug / Windows / Watch / Watch (1, 2, 3, 4)) and QuickWatch (right-click on variable / Debug / QuickWatch) windows to watch variables and expressions during a debugging session. The difference is that the Watch window can display several variables, while the QuickWatch window displays a single variable at a time.
Source : Watch and QuickWatch Windows
Click Shift+F9 or Ctrl+Alt+Q on that part and it open Debug.QuickWatch.
The regular watch window will also show a function return value (so you would have to execute whatever statement you are interested in and possibly even step out of the function). Such unnamed expressions come at the head of the watch window list. The keystroke under my key map is alt+4, you can also get there via Debug->Windows->Watch...
I have a bit of a silly issue:
I have a large number of unit tests which all have method attributes like this:
[TestMethod]
[Owner("me")]
[Description("It tests something.")]
[TestProperty(TC.Name, "Some Test")]
[TestProperty(TC.Requirement, "req203")]
[TestProperty(TC.Reviewer, "someguy")]
[TestProperty(TC.Environment, "MSTest")]
[TestProperty(TC.CreationDate, "24.01.2012")]
[TestProperty(TC.InternalTcId, "{9221A494-2B31-479D-ADE6-D4773C2A9B08}")]
public void TestSomething()
{ ... }
(If you're wondering: these attributes are used for automated testing and requirement coverage stuff.. )
Now, unfortunately these attributes are in a different order at most test methods - which makes it a bit messy to review and such. So I'm looking for a way to order them..
Would you know any other way than rearranging them manually?
(I thought about writing some VS plugin or so) - I'm just wondering whether I'm really the first person with that wish.
Open up the Macro Explorer - and paste this code into a module (It's straight from my own little collection of macros):
Sub Sort()
Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
If selection Is Nothing Or String.IsNullOrWhiteSpace(selection.Text) Then
Exit Sub
End If
Dim lines As String() = selection.Text.Split(vbCrLf.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
If lines.Length <= 1 Then Exit Sub
lines = lines.OrderBy(Function(s As String) s, StringComparer.CurrentCulture).ToArray()
DTE.UndoContext.Open("Sort Lines")
selection.Insert(String.Join(vbCrLf, lines))
selection.SmartFormat()
DTE.UndoContext.Close()
DTE.StatusBar.Text = "Sort Lines complete"
selection.SmartFormat()
End Sub
(just edited it as the try/end try wasn't really right - so I've taken it out)
Now you can bind a shortcut to this macro in VS - it uses a Linq OrderBy using the current culture's string comparer to sort the lines of the currently selected block of text. It should therefore group the attributes together accordingly.
If you need something that context-sensitive (i.e. the same attribute being called with different numbers of parameters) - then you'll need to do considerably more work.
You are the first person with that wish :)
I would arrange them manually, but also, if you are looking for a more solid solution, then I would implement a property in the TestPropertyAttribute class int Index { get; set; } and set the order in which I want them processed. In that case, you can control which how attributes are read in the reflection code that reads them.
This is how NHibernate does it.
[TestProperty(TC.Name, "Some Test", 0)]
[TestProperty(TC.Requirement, "req203", 1)]
Is it possible to automatically return from a function using a Breakpoint/Tracepoint?
I don't want to drag the execution point or set it with CTRL+SHIFT+F10 every time the breakpoint is hit.
I tried "printing" the following "messages" When Hit, but the executions continue without change.
{return;}
{return null;}
Note that I need to return from the function without actually changing code.
To clarify what a Tracepoint is: "A tracepoint is a breakpoint with a custom action associated with it. When a tracepoint is hit, the debugger performs the specified tracepoint action instead of, or in addition to, breaking program execution." From MSDN.
If you don't know what I mean with "printing messages", you might want to read this AltDevBlogADay post about Tracepoints. It's good.
In Visual Studio you could just drag the arrow, that indicates the current code line while debugging, to the end of the function.
Okay, after a bit of digging around you can do this - but it's not going to work in all cases.
Beware, this uses macros and can't be guaranteed to work with inline delegates; or with methods that actually need to return something. It automates the process described by #juergen d and #Erno when a breakpoint is hit; using very simple heuristics to find where the end of the current function is.
You first need to add this macro to your macros environment (open with ALT+F11 in VS). This code is probably not as good as it could be as I've just rushed it out :)
Sub ExitStack()
'get the last-hit breakpoint
Dim breakPoint As EnvDTE.Breakpoint
breakPoint = DTE.Debugger.BreakpointLastHit()
'if the currently open file is the same as where the breakpoint is set
'(could search and open it, but the debugger *should* already have done that)
If (DTE.ActiveDocument.FullName = breakPoint.File) Then
Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
Dim editPoint As EnvDTE.EditPoint
'move the cursor to where the breakpoint is actually defined
selection.MoveToLineAndOffset(breakPoint.FileLine, breakPoint.FileColumn)
Dim codeElement As EnvDTE.CodeElement
codeElement = DTE.ActiveDocument.ProjectItem.FileCodeModel.CodeElementFromPoint(selection.ActivePoint, vsCMElement.vsCMElementFunction)
'if a function is found, move the cursor to the last character of it
If Not (codeElement Is Nothing) Then
Dim lastLine As EnvDTE.TextPoint
lastLine = codeElement.GetEndPoint()
selection.MoveToPoint(lastLine)
selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
'execute the SetNextStatement command.
'Has to be done via ExecuteCommand
DTE.ExecuteCommand("Debug.SetNextStatement")
End If
End If
End Sub
With that in place, now you can set your breakpoint - right click on it and hit the When hit... menu option (this only works in VS2010 I believe). ScottGu describes this in this blog post.
From the dialog, find the ExitStack macro that you've just pasted in.
Run the code with the debugger attached and when the breakpoint is hit the rest of the function's code should be skipped. This should obey other debugger tricks - like conditions etc.
Note - I used this SO to solve a problem I was having; originally I was invoking the debugger's SetNextStatement method directly and it didn't work
I have no idea how methods that should return will behave - in theory they should return whatever the return value local is at the time, but in some cases the fact is this simply won't work!
Equally if the breakpoint is in a try/catch block then it won't work - because the try/catch has to be exited before you can set the next statement to somewhere outside of it.
Two options:
If you want the function to complete its execution and break after returning to the caller. Press "Step Out" (Shift-F11)
If you want to skip the execution of several lines, drag the yellow marker to the next line you want to execute. Remember, dragging the marker to a location might cause an order of execution that can never happen when running without interfering so the result might be completely wrong.
Yes, you can do this directly using a tracepoint.
Find the address of the return statement at the bottom of the function by breaking on it once, and then looking at the EIP register either in the Registers window or add a Watch for "#eip".
Add a tracepoint to the line you want to jump from. Remember that the jump will occur before anything on the line is executed. The content of the tracepoint should be {#eip = address} using the address from step 1.
Profit!
See also https://stackoverflow.com/a/14695736/301729
Greetings Friends,
What is the best way (least amount of keystrokes) to get Visual Studio 2010 to automatically insert the current date and my name/initials whenever I put a single line comment into my codebase? This should support C# and it'd be even better if it worked in my .aspx pages too.
Thanks -- I know someone out there has the perfect solution :).
Create a macro and assign a Shortcut key.
The easiest way is go to Tools->Macros->Macro Explorer and edit one of the samples, I used Samples->VSEditor, right click that one and edit.
Now youre in the Macro editor
Now create this function.
Sub NewCommentLinePersonal()
Dim textSelection As EnvDTE.TextSelection
textSelection = DTE.ActiveWindow.Selection
textSelection.NewLine()
textSelection.Insert(Utilities.LineOrientedCommentStart())
textSelection.Insert(" " + Date.Now + " - Your Initial ")
End Sub
then go to Tools->Options->Environment->Keyboard and type the NewCommentLinePersonal on textbox "Show commands containing:" then choose your shortcut key
Perhaps another way of approaching it, assuming the insertion of a timestamp and name is being done for change tracking, is to lean on source control.
For example, in my current codebase, we deprecated the use of putting in change comments, since we found that the field of green was cluttering things, and if I ever needed to see who changed what, I could simply look in our source control system, and even see how this one change was related to other modifications within the same changeset.