locked
Hosting an XML editor does not reload in Visual Studio properly RRS feed

  • Question

  • I have created a custom IVsEditorFactory to host an XML editor with a WPF control. I found a few examples all using an IVsInvisibleEditorManager like the following:

            Dim textBuffer As IVsTextBuffer
    
            If punkDocDataExisting = IntPtr.Zero Then
                Dim invisibleEditorManager = CType(Me.mServiceProvider.GetService(GetType(SVsInvisibleEditorManager)), IVsInvisibleEditorManager)
    
                Dim invisibleEditor As IVsInvisibleEditor = Nothing
                ErrorHandler.ThrowOnFailure(invisibleEditorManager.RegisterInvisibleEditor(pszMkDocument, Nothing, CUInt(_EDITORREGFLAGS.RIEF_ENABLECACHING), Nothing, invisibleEditor))
    
                Dim docDataPointer = IntPtr.Zero
                ErrorHandler.ThrowOnFailure(invisibleEditor.GetDocData(1, GetType(IVsTextBuffer).GUID, docDataPointer))
    
                textBuffer = CType(Marshal.GetObjectForIUnknown(docDataPointer), IVsTextBuffer)
            Else
                textBuffer = TryCast(Marshal.GetObjectForIUnknown(punkDocDataExisting), IVsTextBuffer)
    
                If textBuffer Is Nothing Then ErrorHandler.ThrowOnFailure(VSConstants.VS_E_INCOMPATIBLEDOCDATA)
            End If
    
            ErrorHandler.ThrowOnFailure(textBuffer.SetLanguageServiceID(Constants.XmlLanguageServiceGuid))
    
            Dim componentModel = CType(Me.mServiceProvider.GetService(GetType(SComponentModel)), IComponentModel)
    
            Dim editorAdapterFactory = componentModel.GetService(Of IVsEditorAdaptersFactoryService)
    
            Dim codeWindow = editorAdapterFactory.CreateVsCodeWindowAdapter(Me.mOleServiceProvider)
    
            ' Disable the splitter which causes a crash
            Dim initView = {New INITVIEW}
            ErrorHandler.ThrowOnFailure(CType(codeWindow, IVsCodeWindowEx).Initialize(CUInt(_codewindowbehaviorflags.CWB_DISABLESPLITTER), VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter, "", "", 0, initView))
    
            ErrorHandler.ThrowOnFailure(codeWindow.SetBuffer(CType(textBuffer, IVsTextLines)))
    
            Dim textView As IVsTextView = Nothing
            ErrorHandler.ThrowOnFailure(codeWindow.GetPrimaryView(textView))
    
            Dim textViewHost = editorAdapterFactory.GetWpfTextViewHost(textView)
    
            If textViewHost Is Nothing Then Return VSConstants.VS_E_INCOMPATIBLEDOCDATA
    
            RemoveParentControl(textViewHost.HostControl)
    
            Dim editor As New HostEditorTestPane(codeWindow, textViewHost)
            ppunkDocView = Marshal.GetIUnknownForObject(editor)
            ppunkDocData = Marshal.GetIUnknownForObject(textBuffer)
            pbstrEditorCaption = ""

    This works on a custom test file when I create and open a project and select the test file. My custom editor opens and intellisense works for the XML editor.

    However, if I open a file in a project and then close Visual Studio, when I reopen the project, it attempts to restore the opened file but it fails on the following line:

    Dim textViewHost = editorAdapterFactory.GetWpfTextViewHost(textView)

    textViewHost is null. By returning VSConstants.VS_E_INCOMPATIBLEDOCDATA Visual Studio then asks to close the file, if I select Yes, it attempts to reopen the file again, but this time punkDocDataExisting is IntPtr.Zero and it successfully opens.

    A slight workaround but that means an annoying message whenever Visual Studio tries to restore a workspace, and also fails to restore other files after. Any idea how to fix this?

    Also, is there any alternative to using IVsInvisibleEditorManager? The original code had a comment about it being easier, but I do know how to get the content type, language service GUID, etc. But when I try to use other methods to create the editor, intellisense and highlighting does not work correctly.

    I created a project and uploaded it here to test https://github.com/manuelxmarquez/HostEditorTest


    • Edited by MannyMarqz Saturday, April 25, 2020 6:41 PM
    Saturday, April 25, 2020 6:39 PM

All replies

  • Hi MannyMarqz,

    It seems that the document is occupied by VS IDE, not the exp version. So I try to install "HostEditorTest.vsix" into VS IDE directly, and then repeat the previous steps,  it could work without this issue. 

    Best Regards,

    Dylan  


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com

    Monday, April 27, 2020 4:56 AM
  • I installed it into a VM and still had the issue.

    I also tried cloning another repo with similar code and had the same issue.

    Monday, April 27, 2020 9:20 PM
  • Hi MannyMarqz,

    Maybe you can refer this gif:

    And you can refer this about the usage of lock and unlock document from here(it is C# code):

    https://stackoverflow.com/a/25450525/11557747

    Best Regards,

    Dylan


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com

    Tuesday, April 28, 2020 8:26 AM
  • I managed to get it working on the user end (it doesn't ask to close the file) but what I found doesn't seem to be the right solution.

    I modified the code to ignore punkDocDataExisting and just create the invisible editor regardless. Commenting out the If and Else, always running the TRUE case.

            'If punkDocDataExisting = IntPtr.Zero Then
            Dim invisibleEditorManager = CType(Me.mServiceProvider.GetService(GetType(SVsInvisibleEditorManager)), IVsInvisibleEditorManager)
    
            Dim invisibleEditor As IVsInvisibleEditor = Nothing
            ErrorHandler.ThrowOnFailure(invisibleEditorManager.RegisterInvisibleEditor(pszMkDocument, Nothing, CUInt(_EDITORREGFLAGS.RIEF_ENABLECACHING), Nothing, invisibleEditor))
    
            Dim docDataPointer = IntPtr.Zero
            ErrorHandler.ThrowOnFailure(invisibleEditor.GetDocData(1, GetType(IVsTextBuffer).GUID, docDataPointer))
    
            textBuffer = CType(Marshal.GetObjectForIUnknown(docDataPointer), IVsTextBuffer)
            'Else
            '    textBuffer = TryCast(Marshal.GetObjectForIUnknown(punkDocDataExisting), IVsTextBuffer)
    
            '    If textBuffer Is Nothing Then ErrorHandler.ThrowOnFailure(VSConstants.VS_E_INCOMPATIBLEDOCDATA)
            'End If

    textViewHost is still null when trying to open the file to restore the workplace and VSConstants.VS_E_INCOMPATIBLEDOCDATA is still returned. The only difference is Visual Studio does not ask to close the file. On the second attempt to open the editor, punkDocDataExisting is IntPtr.Zero and it succeeds to open.

    However, it seems to me like not the correct solution, even though it works. It's almost like Visual Studio opens the file and passes a pointer to a document that is incompatible with the invisible editor or WPF, and the document must be opened by the invisible editor to work correctly.

    I tried your suggestion about locking the document but was unable to find that solution. I think you may be correct though since if I remove _EDITORREGFLAGS.RIEF_ENABLECACHING from the call to RegisterInvisibleEditor, it fails and gives the message to close the file. I tried:

                Dim runningDocumentTable = CType(Me.mServiceProvider.GetService(GetType(SVsRunningDocumentTable)), IVsRunningDocumentTable)
    
                Dim cookie As UInteger
                ErrorHandler.ThrowOnFailure(runningDocumentTable.FindAndLockDocument(CUInt(_VSRDTFLAGS.RDT_EditLock), pszMkDocument, Nothing, Nothing, ppunkDocData, cookie))

    But am I supposed to use punkDocDataExisting passed in to CreateEditorInstance, the return value ppunkDocData from FindAndLockDocument? Do I still call RegisterInvisibleEditor? I tried many possibilities but it still returns null on this line:

    Dim textViewHost = editorAdapterFactory.GetWpfTextViewHost(textView)

    Tuesday, April 28, 2020 7:57 PM