/* **************************************************************************** * * Copyright (c) Microsoft Corporation. * * This source code is subject to terms and conditions of the Apache License, Version 2.0. A * copy of the license can be found in the License.html file at the root of this distribution. If * you cannot locate the Apache License, Version 2.0, please send an email to * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound * by the terms of the Apache License, Version 2.0. * * You must not remove this notice, or any other, from this software. * * ***************************************************************************/ using System; using System.Globalization; using System.Runtime.InteropServices; using Microsoft.VisualStudio.Designer.Interfaces; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; using VSConstants = Microsoft.VisualStudio.VSConstants; namespace Microsoft.VisualStudio.Project { /// /// Common factory for creating our editor /// public abstract class CommonEditorFactory : IVsEditorFactory { private CommonProjectPackage _package; private ServiceProvider _serviceProvider; private readonly bool _promptEncodingOnLoad; public CommonEditorFactory(CommonProjectPackage package) { _package = package; } public CommonEditorFactory(CommonProjectPackage package, bool promptEncodingOnLoad) { _package = package; _promptEncodingOnLoad = promptEncodingOnLoad; } #region IVsEditorFactory Members public virtual int SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider psp) { _serviceProvider = new ServiceProvider(psp); return VSConstants.S_OK; } public virtual object GetService(Type serviceType) { return _serviceProvider.GetService(serviceType); } // This method is called by the Environment (inside IVsUIShellOpenDocument:: // OpenStandardEditor and OpenSpecificEditor) to map a LOGICAL view to a // PHYSICAL view. A LOGICAL view identifies the purpose of the view that is // desired (e.g. a view appropriate for Debugging [LOGVIEWID_Debugging], or a // view appropriate for text view manipulation as by navigating to a find // result [LOGVIEWID_TextView]). A PHYSICAL view identifies an actual type // of view implementation that an IVsEditorFactory can create. // // NOTE: Physical views are identified by a string of your choice with the // one constraint that the default/primary physical view for an editor // *MUST* use a NULL string as its physical view name (*pbstrPhysicalView = NULL). // // NOTE: It is essential that the implementation of MapLogicalView properly // validates that the LogicalView desired is actually supported by the editor. // If an unsupported LogicalView is requested then E_NOTIMPL must be returned. // // NOTE: The special Logical Views supported by an Editor Factory must also // be registered in the local registry hive. LOGVIEWID_Primary is implicitly // supported by all editor types and does not need to be registered. // For example, an editor that supports a ViewCode/ViewDesigner scenario // might register something like the following: // HKLM\Software\Microsoft\VisualStudio\9.0\Editors\ // {...guidEditor...}\ // LogicalViews\ // {...LOGVIEWID_TextView...} = s '' // {...LOGVIEWID_Code...} = s '' // {...LOGVIEWID_Debugging...} = s '' // {...LOGVIEWID_Designer...} = s 'Form' // public virtual int MapLogicalView(ref Guid logicalView, out string physicalView) { // initialize out parameter physicalView = null; bool isSupportedView = false; // Determine the physical view if (VSConstants.LOGVIEWID_Primary == logicalView || VSConstants.LOGVIEWID_Debugging == logicalView || VSConstants.LOGVIEWID_Code == logicalView || VSConstants.LOGVIEWID_TextView == logicalView) { // primary view uses NULL as pbstrPhysicalView isSupportedView = true; } else if (VSConstants.LOGVIEWID_Designer == logicalView) { physicalView = "Design"; isSupportedView = true; } if (isSupportedView) return VSConstants.S_OK; else { // E_NOTIMPL must be returned for any unrecognized rguidLogicalView values return VSConstants.E_NOTIMPL; } } public virtual int Close() { return VSConstants.S_OK; } /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// public virtual int CreateEditorInstance( uint createEditorFlags, string documentMoniker, string physicalView, IVsHierarchy hierarchy, uint itemid, System.IntPtr docDataExisting, out System.IntPtr docView, out System.IntPtr docData, out string editorCaption, out Guid commandUIGuid, out int createDocumentWindowFlags) { // Initialize output parameters docView = IntPtr.Zero; docData = IntPtr.Zero; commandUIGuid = this.GetType().GUID; createDocumentWindowFlags = 0; editorCaption = null; // Validate inputs if ((createEditorFlags & (VSConstants.CEF_OPENFILE | VSConstants.CEF_SILENT)) == 0) { return VSConstants.E_INVALIDARG; } // Get a text buffer IVsTextLines textLines = GetTextBuffer(docDataExisting); // Assign docData IntPtr to either existing docData or the new text buffer if (docDataExisting != IntPtr.Zero) { docData = docDataExisting; Marshal.AddRef(docData); } else { docData = Marshal.GetIUnknownForObject(textLines); } try { docView = CreateDocumentView(documentMoniker, physicalView, hierarchy, itemid, textLines, out editorCaption, out commandUIGuid); } finally { if (docView == IntPtr.Zero) { if (docDataExisting != docData && docData != IntPtr.Zero) { // Cleanup the instance of the docData that we have addref'ed Marshal.Release(docData); docData = IntPtr.Zero; } } } return VSConstants.S_OK; } #endregion #region Helper methods private IVsTextLines GetTextBuffer(System.IntPtr docDataExisting) { IVsTextLines textLines; if (docDataExisting == IntPtr.Zero) { // Create a new IVsTextLines buffer. Type textLinesType = typeof(IVsTextLines); Guid riid = textLinesType.GUID; Guid clsid = typeof(VsTextBufferClass).GUID; textLines = _package.CreateInstance(ref clsid, ref riid, textLinesType) as IVsTextLines; // set the buffer's site ((IObjectWithSite)textLines).SetSite(_serviceProvider.GetService(typeof(IOleServiceProvider))); } else { // Use the existing text buffer Object dataObject = Marshal.GetObjectForIUnknown(docDataExisting); textLines = dataObject as IVsTextLines; if (textLines == null) { // Try get the text buffer from textbuffer provider IVsTextBufferProvider textBufferProvider = dataObject as IVsTextBufferProvider; if (textBufferProvider != null) { textBufferProvider.GetTextBuffer(out textLines); } } if (textLines == null) { // Unknown docData type then, so we have to force VS to close the other editor. ErrorHandler.ThrowOnFailure((int)VSConstants.VS_E_INCOMPATIBLEDOCDATA); } } return textLines; } private IntPtr CreateDocumentView(string documentMoniker, string physicalView, IVsHierarchy hierarchy, uint itemid, IVsTextLines textLines, out string editorCaption, out Guid cmdUI) { //Init out params editorCaption = string.Empty; cmdUI = Guid.Empty; if (string.IsNullOrEmpty(physicalView)) { // create code window as default physical view return CreateCodeView(documentMoniker, textLines, ref editorCaption, ref cmdUI); } else if (string.Compare(physicalView, "design", true, CultureInfo.InvariantCulture) == 0) { // Create Form view return CreateFormView(hierarchy, itemid, textLines, ref editorCaption, ref cmdUI); } // We couldn't create the view // Return special error code so VS can try another editor factory. ErrorHandler.ThrowOnFailure((int)VSConstants.VS_E_UNSUPPORTEDFORMAT); return IntPtr.Zero; } private IntPtr CreateFormView(IVsHierarchy hierarchy, uint itemid, IVsTextLines textLines, ref string editorCaption, ref Guid cmdUI) { // Request the Designer Service IVSMDDesignerService designerService = (IVSMDDesignerService)GetService(typeof(IVSMDDesignerService)); // Create loader for the designer IVSMDDesignerLoader designerLoader = (IVSMDDesignerLoader)designerService.CreateDesignerLoader("Microsoft.VisualStudio.Designer.Serialization.VSDesignerLoader"); bool loaderInitalized = false; try { IOleServiceProvider provider = _serviceProvider.GetService(typeof(IOleServiceProvider)) as IOleServiceProvider; // Initialize designer loader designerLoader.Initialize(provider, hierarchy, (int)itemid, textLines); loaderInitalized = true; // Create the designer IVSMDDesigner designer = designerService.CreateDesigner(provider, designerLoader); // Get editor caption editorCaption = designerLoader.GetEditorCaption((int)READONLYSTATUS.ROSTATUS_Unknown); // Get view from designer object docView = designer.View; // Get command guid from designer cmdUI = designer.CommandGuid; return Marshal.GetIUnknownForObject(docView); } catch { // The designer loader may have created a reference to the shell or the text buffer. // In case we fail to create the designer we should manually dispose the loader // in order to release the references to the shell and the textbuffer if (loaderInitalized) { designerLoader.Dispose(); } throw; } } private IntPtr CreateCodeView(string documentMoniker, IVsTextLines textLines, ref string editorCaption, ref Guid cmdUI) { Type codeWindowType = typeof(IVsCodeWindow); Guid riid = codeWindowType.GUID; Guid clsid = typeof(VsCodeWindowClass).GUID; IVsCodeWindow window = (IVsCodeWindow)_package.CreateInstance(ref clsid, ref riid, codeWindowType); ErrorHandler.ThrowOnFailure(window.SetBuffer(textLines)); ErrorHandler.ThrowOnFailure(window.SetBaseEditorCaption(null)); ErrorHandler.ThrowOnFailure(window.GetEditorCaption(READONLYSTATUS.ROSTATUS_Unknown, out editorCaption)); IVsUserData userData = textLines as IVsUserData; if (userData != null) { if (_promptEncodingOnLoad) { var guid = VSConstants.VsTextBufferUserDataGuid.VsBufferEncodingPromptOnLoad_guid; userData.SetData(ref guid, (uint)1); } } InitializeLanguageService(textLines); cmdUI = VSConstants.GUID_TextEditorFactory; return Marshal.GetIUnknownForObject(window); } /// /// Initializes the language service for the given file. This allows files with different /// extensions to be opened by the editor type and get correct highlighting and intellisense /// controllers. /// /// New in 1.1 /// protected virtual void InitializeLanguageService(IVsTextLines textLines) { } #endregion } }