I'm trying to create an extension VSPackage for VS2017 (in C#) which would convert binary data to XML, opens that in the default VS XML editor and XML language service, and then converts it back to binary upon saving.
However, I have troubles to line out which steps would be required for this. I thought of the following for now when creating a new editor in the editor factory:
- Create new text buffer
- Feed it with converted XML data
- Create core editor
- Feed it with the text buffer
Right now my attempt looks like this:
private MyPackage _package; // Filled via constructor
private IServiceProvider _serviceProvider; // Filled via SetSite
public int CreateEditorInstance(uint grfCreateDoc, string pszMkDocument, string pszPhysicalView,
IVsHierarchy pvHier, uint itemid, IntPtr punkDocDataExisting, out IntPtr ppunkDocView,
out IntPtr ppunkDocData, out string pbstrEditorCaption, out Guid pguidCmdUI, out int pgrfCDW)
{
// Initialize and validate parameters.
ppunkDocView = IntPtr.Zero;
ppunkDocData = IntPtr.Zero;
pbstrEditorCaption = String.Empty;
pguidCmdUI = Guid.Empty;
pgrfCDW = 0;
VSConstants.CEF createDocFlags = (VSConstants.CEF)grfCreateDoc;
if (!createDocFlags.HasFlag(VSConstants.CEF.OpenFile) && !createDocFlags.HasFlag(VSConstants.CEF.Silent))
return VSConstants.E_INVALIDARG;
if (punkDocDataExisting != IntPtr.Zero)
return VSConstants.VS_E_INCOMPATIBLEDOCDATA;
// Create a sited IVsTextBuffer storing the converted data with the XML data and language service set.
IVsTextLines textLines = _package.CreateComInstance<VsTextBufferClass, IVsTextLines>();
SiteObject(textLines);
string xmlText = BinaryXmlData.GetXmlString(pszMkDocument);
textLines.InitializeContent(xmlText, xmlText.Length);
ErrorHandler.ThrowOnFailure(textLines.SetLanguageServiceID(ref Guids.XmlLanguageServiceGuid));
// Instantiate a sited IVsCodeWindow and feed it with the text buffer.
IVsCodeWindow codeWindow = _package.CreateComInstance<VsCodeWindowClass, IVsCodeWindow>();
SiteObject(codeWindow);
codeWindow.SetBuffer(textLines);
// Return the created instances to the caller.
ppunkDocView = Marshal.GetIUnknownForObject(codeWindow);
ppunkDocData = Marshal.GetIUnknownForObject(textLines);
return VSConstants.S_OK;
}
private void SiteObject(object obj)
{
(obj as IObjectWithSite)?.SetSite(_serviceProvider);
}
// --- CreateComInstance is a method on my package ----
internal TInterface CreateComInstance<TClass, TInterface>()
{
Guid guidT = typeof(TClass).GUID;
Guid guidInterface = typeof(TInterface).GUID;
TInterface instance = (TInterface)CreateInstance(ref guidT, ref guidInterface, typeof(TInterface));
if (instance == null)
throw new COMException($"Could not instantiate {typeof(TClass).Name} / {typeof(TInterface).Name}.");
return instance;
}
When I try to explicitly open a file with my editor, it states "The file cannot be opened with the selected editor. Please choose another editor." The message doesn't make sense to me, I tried to open XML data with the XML editor, but it somehow still tries to open a text editor with the binary data.
I'm stuck here, I did all I could think of to feed it converted data. Apparently this way is not the right one.
- How could I add steps inbetween to fetch the binary data, quickly convert it to XML, then feed it to the XML editor?
- How would I store it back as binary when the XML editor saves the file?
- Is it possible at all to reuse the XML editor and language services for this?
I'm sorry if these questions require lengthy answers; I'd be happy already if I could get pointed in the right direction or to some already open-sourced extension doing something similar (converting file data before displaying it in a VS code editor).