2

I've read several articles that tell you how to add text to the output window in visual studio from within an Add-On (specifically, a visual studio 2008 integration package, via the visual studio 2008 SDK 1.1), but no examples of how to read text from the output window. My goal is to parse text from the debug output window while debugging a certain application (TRACE output and possibly stdin/stdout). The IVsOutputWindowPane interface has no methods for reading in text from the output window. The documentation seems to imply that it is possible, but it doesn't provide an example:

http://msdn.microsoft.com/en-us/library/bb166236(VS.80).aspx

Quote: In addition, the OutputWindow and OutputWindowPane objects add some higher-level functionality to make it easier to enumerate the Output window panes and to retrieve text from the panes.

Preferably I'd like to be able to subscribe to an event that fires when a new line of text arrives, similar to a StreamReader's asynchronous reads.

Jeremy Bell
  • 5,253
  • 5
  • 41
  • 63

4 Answers4

4

It is possible, it is just a long winding path to get to it:

ServiceProvider -> IVsOutputWindow -> GetPane( debugwindow ) -> IVsUserData -> GetData( wpftextviewhost ) -> IWpfTextViewHost -> IWpfTextView -> TextBuffer -> Changed event.

Presuming you have a VS IServiceProvider from somewhere else (vsix extension/whatever, global service provider), and without any error checking, it looks like this:

IVsOutputWindow outWindow = ServiceProvider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
IVsOutputWindowPane pane;
outWindow.GetPane(ref debugPaneGuid, out pane);
// from here up you'll find in lots of other stackoverflow answers, 

// the stuff from here down is interesting to this question
IVsUserData userData = (IVsUserData)pane;
object o;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out o);

IWpfTextViewHost viewHost = (IWpfTextViewHost)o;
IWpfTextView textView = viewHost.TextView;
textView.TextBuffer.Changed += YourTextChangedHandlerHere;

Your text changed handler will then get called every time the output window gets more data. you won't necessarily get it line by line, but you'll probably more likely than not get big chunks you'll need to deal with on your own.

It is highly likely that some of the above did not even exist in VS in 2010. But it exists now!

John Gardner
  • 24,225
  • 5
  • 58
  • 76
1

The default behavior (when you don’t set the listener explicitly) of VS is to display trace massages in the debugger output window, which you appreciate if you want a simple solution and do no other actions with the massages.

Unfortunately this is not your case. So you have to define a trace listener to send (and store) your trace massages where you then will be able to read them. The trace listener could be a file (for example XML) or you can create a custom listener by deriving a class from the base class TraceListener if you don't want to bother yourself with an additional file.

Machta
  • 1,656
  • 2
  • 16
  • 28
  • How would a trace listener capture what goes to the output window? – John Saunders Mar 07 '10 at 11:13
  • Nice edit, but still, a tracelistener would only capture trace messages. That's not all that goes into the Output window. – John Saunders Mar 07 '10 at 11:33
  • OK, that’s true. If this is enough for the user he can use this solution, but I admit this is not the way of acquiring everything written in the Output window. – Machta Mar 07 '10 at 11:45
  • I would be satisfied with just being able to capture trace output - but it seems the documentation is hinting that direct access to the output window pane text is possible (see edit to my original post). That would be the preferable solution if it were actually possible. Is the documentation simply incorrect/misleading? That wouldn't surprise me. – Jeremy Bell Mar 08 '10 at 14:21
  • You say that it dosn't provide an example... I can see at least 4. – Machta Mar 08 '10 at 14:39
  • So If I understand you well, you don't need to use this approach, but you are curious, whether the documentation contains any mistakes. – Machta Mar 08 '10 at 14:50
  • I tried to do something with the IVsOutputWindow, so I added the using directive and tried to add Microsoft.VisualStudio.Shell.Interop.dll assembly reference, but the assembly was not in the VS add reference .Net list... I don't even dare imagine how many more bugs/mistakes/problems you will have to pass and solve to complete this seems-to-be-easy question... I surrender. Good luck to you brother, you will need – Machta Mar 08 '10 at 16:08
  • The examples all show how to write text to the output window, but not how to read text. I did some experimentation with getting the OutputWindowPane. OutputWindowPane has a TextDocument property, but TextDocument doesn't seem to have any way of getting the text from the document directly. The only way I could figure out was to call OutputWindowPane.TextDocument.Selection.SelectAll() and then OutputWindowPane.TextDocument.Selection.Text. I had to queue up a background worker to do this every few seconds, check if there was new text, and parse the new text. There has to be a better way... – Jeremy Bell Mar 08 '10 at 16:25
  • 1
    only 4 years late, I did find a way to do this without a thread using IWpfTextView, which might not have even existed in 2010 :) – John Gardner Apr 02 '14 at 01:03
1

I don't know that what you ask is possible. But, you can register your add-in as a debugger for your application so that you get the output the trace messages. These are typically routed to OutputDebugString, and can be captured as described in this article: http://www.drdobbs.com/showArticle.jhtml?articleID=184410719. It does not give you the normal output, only debug, but it does not depend on the technology of the debugged application.

0

The solution on this page selects the text in order to read it. I'm hoping there's a better way. Automatically stop Visual C++ 2008 build at first compile error?

Private Sub OutputWindowEvents_OnPaneUpdated(ByVal pPane As OutputWindowPane) Handles OutputWindowEvents.PaneUpdated
    pPane.TextDocument.Selection.SelectAll()
    Dim Context As String = pPane.TextDocument.Selection.Text
    pPane.TextDocument.Selection.EndOfDocument()
End Sub
Community
  • 1
  • 1
Jon
  • 5,275
  • 5
  • 39
  • 51