I'm committed to bringing an improved Disassembly Window experience in VS for free. However, the disassembly window is different compared to other windows. Good example code is available for the current API (see for example here). Sadly, the disassembly window uses an older legacy API which is, well, barely documented. See also these questions on MSDN and GitHub. I can't even find example code that compiles with current versions of VS (vs2015/17).
Question: how to make a popup in the Disassembly Window.
Ads: What can you get in return (for helping me solve this question; for asking your grumpy yet knowledgeable colleague; for reposting it to your grandma)? Answer: A free VS extension that adds:
To answer and document my meandering experiences.
Extend IIntellisenseControllerProvider:
[Export(typeof(IIntellisenseControllerProvider))]
[ContentType("Disassembly")]
[TextViewRole(PredefinedTextViewRoles.Debuggable)]
internal sealed class MyInfoControllerProvider : IIntellisenseControllerProvider
{
[Import]
private IQuickInfoBroker _quickInfoBroker = null;
[Import]
private IToolTipProviderFactory _toolTipProviderFactory = null;
public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers)
{
var provider = this._toolTipProviderFactory.GetToolTipProvider(textView);
return new MyInfoController(textView, subjectBuffers, this._quickInfoBroker, provider);
}
}
The constructor of MyInfoController look like this:
internal MyInfoController( ITextView textView, IList<ITextBuffer> subjectBuffers, IQuickInfoBroker quickInfoBroker, IToolTipProvider toolTipProvider) { this._textView = textView; this._subjectBuffers = subjectBuffers; this._quickInfoBroker = quickInfoBroker; this._toolTipProvider = toolTipProvider; this._textView.MouseHover += this.OnTextViewMouseHover; }
The OnTextViewMouseHover handles the creation of the popup:
private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e)
{
SnapshotPoint? point = GetMousePosition(new SnapshotPoint(this._textView.TextSnapshot, e.Position));
if (point.HasValue)
{
string contentType = this._textView.TextBuffer.ContentType.DisplayName;
if (contentType.Equals("Disassembly"))
{
this.ToolTipLegacy(point.Value);
}
else // handle Tooltip the regular way
{
if (!this._quickInfoBroker.IsQuickInfoActive(this._textView))
{
ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive);
this._session = this._quickInfoBroker.CreateQuickInfoSession(this._textView, triggerPoint, false);
this._session.Start();
}
}
}
}
Handle the creation of the tooltip in ToolTipLegacy:
private void ToolTipLegacy(SnapshotPoint triggerPoint)
{
// retrieve what is under the triggerPoint, and make a trackingSpan.
var textBlock = new TextBlock() { Text = "Bla" };
textBlock.Background = TODO; //do not forget to set a background
this._toolTipProvider.ShowToolTip(trackingSpan, textBlock, PopupStyles.DismissOnMouseLeaveTextOrContent);
}