Search code examples
c#visual-studiovisual-studio-2013vspackage

IVsInvisibleEditorManager not placing document within Running Document Table


I'm working on a Visual Studio package and I seem to be running into an issue with IVsInvisibleEditorManager and the Running Document Table (RDT).

To start, I have a file opened within a normal Visual Studio editor. Next, I register an IVsInvisibleEditor for this same file via:

IVsInvisibleEditor invisibleEditor;
ErrorHandler.ThrowOnFailure(this._InvisibleEditorManager.RegisterInvisibleEditor(
    filePath
    , pProject: null
    , dwFlags: (uint)_EDITORREGFLAGS.RIEF_ENABLECACHING
    , pFactory: null
    , ppEditor: out invisibleEditor));

When I modify the file and close the primary Visual Studio editor, I am prompted with a message to save my document. My understanding is that this should not be the case as I still have access to this file within my invisible editor. Visual Studio then cleans up some of the resources associated with this file, which breaks my invisible editor.

I suspect this is because RegisterInvisibleEditor() is not correctly registering my document within the RDT.

The documentation for RegisterInvisibleEditor() states the following for dwFlags when using _EDITORREGFLAGS.RIEF_ENABLECACHING:

This allows the document to stay in the RDT in the scenario where a document is open in a visible editor, and closed by the user while an invisible editor is registered for that document.

This describes my problem exactly. The visible editor is being closed, but I'd like the document to remain in the RDT.

Does anyone know how to make my document persists within the RDT?

Is the RDT project specific? Does the fact that I'm passing in null for both pProject and pFactory cause any problems for the RDT?

Edit: I just tested the above code out, but passed in the appropriate IVsProject and there was no change. It still appears the RDT is not changed when registering an invisible editor.


Solution

  • It doesn't appear as though I can convince the IVsInvisibleEditorManager to add a lock to the document. Unfortunately, RegisterInvisibleEditor() is a COM method, which means I can't decompile and peek at what it's doing (at least to my limited knowledge).

    However, I've come up with a workaround in which I manually manage entries within the RDT.

    var rdt =
    (IVsRunningDocumentTable)GetService(typeof(SVsRunningDocumentTable)); 
    //Retrieve the appropriate IVsHierarchy. I've assumed there's only
    //one project within this solution. 
    var solutionService = (IVsSolution)GetService(typeof(SVsSolution));
    IVsProject project = null;
    Guid guid = Guid.Empty;
    solutionService.GetProjectEnum((uint)__VSENUMPROJFLAGS.EPF_LOADEDINSOLUTION, ref guid, out enumerator);
    var hierarchy = new IVsHierarchy[1] { null };
    uint fetched = 0;
    for((enumerator.Reset(); enumerator.Next(1, hierarchy, out fetched) == VSConstants.S_OK && fetched == 1;)
         hierarchy = hierarchyArray[0]
    
    //Then when creating the IVsInvisibleEditor, find and lock the document 
    uint itemID;
    IntPtr docData;
    uint docCookie;
    var result = rdt.FindAndLockDocument(
        dwRDTLockType: (uint)_VSRDTFLAGS.RDT_ReadLock
        , pszMkDocument: filePath
        , ppHier: out hierarchy
        , pitemid: out itemID
        , ppunkDocData: out docData
        , pdwCookie: out docCookie
        );
    

    At some point you'll be finished with your IVsInvisibleEditor, at which point you should unlock the document from the RDT.

    runningDocTable.UnlockDocument((uint)_VSRDTFLAGS.RDT_ReadLock, docCookie);