2

In the picture below I'm on a breakpoint looping through the (196) elements of a TStrings. The current index is 193.

The Visualizer only shows 17 elements.

Can anything be done about that (other than specifically inspecting element 'x')?

enter image description here

Jan Doggen
  • 8,799
  • 13
  • 70
  • 144
  • I think the way the visualizers work is that the debugger has some fixed buffer size per inspected expression, and what you're seeing is how many of your lines fit into 2k or 4k bytes, and this is a limitation of the visualizer feature within the debugger. If they added some up/down arrows or a way to interact with the thing, maybe they could let you scroll through more data. – Warren P Dec 31 '15 at 15:43
  • @Warren I'll check that out next year ;-) with shorter strings – Jan Doggen Dec 31 '15 at 17:38
  • Since you can write your own visualizers, it is possible you could add such arrows, and use a different control to show the contents. – Warren P Dec 31 '15 at 18:13

1 Answers1

2

As far as I can tell, there's not much that you can do about this, short of submitting a feature request (and upgrading if it succeeds). My guess it that's what's being truncated, like WarrenP implied, is the size of the data being fed to the visualizer, rather than the particular number of lines in the TStrings object. This is why I think that:

Assuming XE2 comes with the same sample debugger visualizers as later XE versions, you could try this:

  1. Uninstall the Embarcadero Sample Visualizers package if you have it installed in the IDE.

  2. Copy the StringListVisualizer.Pas unit to somewhere convenient.

  3. Create a new .Dpk project and add the copied StringListVisualizer.Pas to its Contains list; its Requires list should include Rtl and DesignIDE.

  4. Open the copied StringListVisualizer.Pas and locate the routine

    function TStringListViewerFrame.Evaluate(Expression: string): string;

You'll see that its local vars include

  ResultStr: array[0..4095] of Char;

Change the 4095 to 32767. The point of doing this is to make sure that the the Strings Visualizer display isn't truncated because of the size of this buffer, in light of WarrenP's comment. In fact the truncation that's causing your problem is seemingly elsewhere.

  1. In StringListVisualizer.Pas, put debugger breakpoints on the lines

      case EvalRes of
    

and

      if not FDeferredError then

in function TStringListViewerFrame.Evaluate(Expression: string): string.

You need 2 breakpoints because there are two ways Evaluate can complete, depending on the value of EvalRes. It always returns erDeferred for me.

  1. Compile and run your Dpk project. It will invoke a second instance of the IDE.

  2. In the second instance, load and run your problem project. When your breakpoint in that trips, right-click in the Watches window and go to Visualizers | Show Strings.

  3. Shortly one or other of your breakpoints in StringListVisualizer.Pas will trip evaluating the strings property that's giving you trouble (it may trip on several other expressions to evaluate first. When it does, single step to where the result of function TStringListViewerFrame.Evaluate is assigned, then evaluate

    Length(Result)

and

Copy(Result, Length(Result) - 100, Length(Result))

Using my test data, I get a value for Length(Result) which is 4101, and the Copy evaluates to the last part of the strings .text, just before its display in the visualizer gets truncated.

It seems fairly clear from those results (in my case at least, ymmv) that the data truncation occurs somewhere in the debugger machinery that feeds the visualizer rather than in the visualizer itself. Somebody who knows more about the debugger internals than me may be able to suggest another way of getting untruncated data to be fed to the visualizer.

Update: A couple of thoughts:

  1. A work-around for the apparent "4k" truncation of what's available to a visualizer might be to link into the app being debugged a function, let's call it TStringsPagedWindow(Input : TStsrings; Page : Integer) : String which returns a section of a TStrings object hopefully working around the "4k" limitation, at the expense of needing to watch it, rather than the TStrings object per se, in the Watch Window, and specify the Page value. Obviously this would not be wildly convenient, and would require the TStringsPagedWindow function to be linked into the executable being debugged.

  2. Following on from 1., seeing as a debugger visualizer can apparently evaluate any valid expression, one could envisage constructing (in the visualizer) an expression based on the name of the TStrings variable being watched and invoking TStringsPagedWindow automatically to populate a GUI object that could display its contents. This is the closest I can think of at the moment to WarrenP's suggestion "Since you can write your own visualizers, it is possible you could add such arrows, and use a different control to show the contents. " Maybe quite a lot of work, but my idea of fun; perhaps I'll have a go if there's any interest.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • "*what's being truncated ... is the size of the data being fed to the visualizer*" - the visualizer itself, not the feeder, decides how much data to retreive. The default `TStrings` visualizer (see `$(BDS)\source\Visualizers\StringListVisualizer.pas`) uses a fixed-sized 4K buffer when evaluating the `TStrings` data. There are 3rd party `TStrings` visualizers floating around that remove that limitation. – Remy Lebeau Dec 31 '15 at 20:57
  • @RemyLebeau: In that case, where in StringListVisualizer.Pas is that fixed buffer size specified? As I said in my answer, the only buffer size specified in the (Xe4 version of the) unit that can be apparently be changed doesn't make any difference (I've tried changing it to 0..32767 or any value in between) - see point 4 - without avoiding the 4k truncation. – MartynA Dec 31 '15 at 21:01
  • There is a fixed buffer inside the `TStringListViewerFrame.Evaluate()` method (`ResultStr: array[0..4095] of Char`) when it is calling the debugger's `IOTAThread.Evaluate()` method. – Remy Lebeau Dec 31 '15 at 21:06
  • @RemyLebeau: That's **exactly** what I said, and also like I said, changing it doesn't seem to make any difference. – MartynA Dec 31 '15 at 21:08
  • After some further research, apparently `IOTAThread.Evaluate()` itself has a 12K limitation. But there are ways to get around that. The answer I just linked this question to explains one way to implement it. – Remy Lebeau Dec 31 '15 at 21:09
  • @RemyLebeau: I'll try out that other answer later but meanwhile, I'm not convinced, Mr Schuster's contribution notwithstanding. It seems to me that something outside StringListVisualizer.pas is imposing a 4k limit, not a 12k one! – MartynA Dec 31 '15 at 21:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99433/discussion-between-remy-lebeau-and-martyna). – Remy Lebeau Dec 31 '15 at 22:11
  • Whoa! Thanks people, but I think I'll live with the current shortcomings for now it is going to be that much work. I have work to do ;-) – Jan Doggen Jan 01 '16 at 12:27
  • @JanDoggen: I imagined you would, and no worries. Anyway, thanks for a v interesting q. – MartynA Jan 01 '16 at 12:42