Partager via


Registering a Language Service (Managed Package Framework)

A managed package framework (MPF) language service is proffered by a VSPackage (see VSPackages) and must be registered with Visual Studio by adding registry keys and entries. This registration process is done in two parts:

  1. Through the registry during installation.

  2. Proffering the service at runtime.

The Registry

There are five user attributes in Visual C# that simplify the process of installing a language service in the registry. These are:

  • ProvideServiceAttribute

  • ProvideLanguageServiceAttribute

  • ProvideLanguageExtensionAttribute

  • ProvideLanguageCodeExpansionAttribute

  • ProvideLanguageEditorOptionPageAttribute

ProvideServiceAttribute

This attribute registers your language service as a service. See the ProvideServiceAttribute class.

Example

using Microsoft.VisualStudio.Shell;

namespace MyLanguagePackage
{
    [ProvideServiceAttribute(typeof(MyLanguageService),
                             ServiceName = "My Language Service")]

    public class MyLanguagePackage : Package
    {
    }
}

ProvideLanguageServiceAttribute

This attribute registers your language service as a language service. This attribute also allows you to set various options that specify what features your language service offers. The example shows only some of the options a language service can provide. See the ProvideLanguageServiceAttribute class.

Example

using Microsoft.VisualStudio.Shell;

namespace MyLanguagePackage
{
    [ProvideLanguageServiceAttribute(typeof(MyLanguageService),
                             "My Language",
                             106,             // resource ID of localized language name
                             CodeSense = true,             // Supports IntelliSense
                             RequestStockColors = false,   // Supplies custom colors
                             EnableCommenting = true,      // Supports commenting out code
                             EnableAsyncCompletion = true  // Supports background parsing
                             )]

    public class MyLanguagePackage : Package
    {
    }
}

ProvideLanguageExtensionAttribute

This attribute associates your language service with a file extension. This way, whenever a file with that extension is loaded, in any project, your language service is started and used to display the contents of the file. See the ProvideLanguageExtensionAttribute class.

Example

using Microsoft.VisualStudio.Shell;

namespace MyLanguagePackage
{
    [ProvideLanguageExtensionAttribute(typeof(MyLanguageService),
                                       ".myext")]

    public class MyLanguagePackage : Package
    {
    }
}

ProvideLanguageCodeExpansionAttribute

This attribute registers a location from which code expansion or snippet templates are obtained. This information is used by the Code Snippets Browser and whenever a code snippet is inserted into the source file. See the ProvideLanguageCodeExpansionAttribute class.

Example

using Microsoft.VisualStudio.Shell;

namespace MyLanguagePackage
{
    [ProvideLanguageCodeExpansionAttribute(
             typeof(MyLanguageService),
             "My Language", // Name of language used as registry key.
             106,           // Resource ID of localized name of language service.
             "mylanguage",  // language key used in snippet templates.
             @"%InstallRoot%\My Language\SnippetsIndex.xml",  // Path to snippets index
             SearchPaths = @"%InstallRoot%\My Language\Snippets\%LCID%\Snippets\;" +
                           @"%MyDocs%\Code Snippets\My Language\My Code Snippets"
             )]

    public class MyLanguagePackage : Package
    {
    }
}

ProvideLanguageEditorOptionPageAttribute

This attribute registers a property page to be displayed in the Tools -> Options dialog box under the Text Editor category. Use one of these attributes for each page to be displayed for your language service. If you need to organize your pages in a tree structure, use additional attributes to define each node of the tree. See the ProvideLanguageEditorOptionPageAttribute class.

Example

This example shows two property pages, Options and Indenting, and one node that contains the second property page.

using Microsoft.VisualStudio.Shell;

namespace MyLanguagePackage
{
    [ProvideLanguageEditorOptionAttribute(
             "My Language",  // Registry key name for language
             "Options",      // Registry key name for property page
             "#242",         // Localized name of property page
             OptionPageGuid = "{A2FE74E1-FFFF-3311-4342-123052450768}"  // GUID of property page
             )]
    [ProvideLanguageEditorOptionAttribute(
             "My Language",  // Registry key name for language
             "Advanced",     // Registry key name for node
             "#243",         // Localized name of node
             )]
    [ProvideLanguageEditorOptionAttribute(
             "My Language",  // Registry key name for language
             @"Advanced\Indenting",     // Registry key name for property page
             "#244",         // Localized name of property page
             OptionPageGuid = "{A2FE74E2-FFFF-3311-4342-123052450768}"  // GUID of property page
             )]

    public class MyLanguagePackage : Package
    {
    }
}

Proffering the Language Service

When your language package is loaded and instantiated, you must tell Visual Studio that your language service is ready. You do this by proffering the service. In your version of the Package class, this is done in the Initialize method. In addition, you need to start a timer that calls your language service during idle periods so background parsing can be accomplished. This idle timer is also used to update document properties if you have implemented any through the DocumentProperties class. In order to support a timer, your package must implement the IOleComponent interface (only the FDoIdle method needs to be fully implemented; the remaining methods can return default values).

Example

This example shows a typical approach to proffering a service and supplying an idle timer.

using System.ComponentModel.Design;
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.Ole.Interop;
using Microsoft.VisualStudio.TextManager.Interop;

namespace MyLanguagePackage
{
    public class MyLanguagePackage : Package, IOleComponent
    {
        private uint m_componentID;


        protected override void Initialize()
        {
            base.Initialize();  // required

            // Proffer the service.
            IServiceContainer serviceContainer = this as IServiceContainer;
            MyLanguageService langService      = new MyLanguageService();
            langService.SetSite(this);
            serviceContainer.AddService(typeof(MyLanguageService),
                                        langService,
                                        true);

            // Register a timer to call our language service during
            // idle periods.
            IOleComponentManager mgr = GetService(typeof(SOleComponentManager))
                                       as IOleComponentManager;
            if (m_componentID == 0 && mgr != null)
            {
                OLECRINFO[] crinfo = new OLECRINFO[1];
                crinfo[0].cbSize            = (uint)Marshal.SizeOf(typeof(OLECRINFO));
                crinfo[0].grfcrf            = (uint)_OLECRF.olecrfNeedIdleTime |
                                              (uint)_OLECRF.olecrfNeedPeriodicIdleTime;
                crinfo[0].grfcadvf          = (uint)_OLECADVF.olecadvfModal     |
                                              (uint)_OLECADVF.olecadvfRedrawOff |
                                              (uint)_OLECADVF.olecadvfWarningsOff;
                crinfo[0].uIdleTimeInterval = 1000;
                int hr = mgr.FRegisterComponent(this, crinfo, out m_componentID);
            }
        }


        protected override void Dispose(bool disposing)
        {
            if (m_componentID != 0)
            {
                IOleComponentManager mgr = GetService(typeof(SOleComponentManager))
                                           as IOleComponentManager;
                if (mgr != null)
                {
                    int hr = mgr.FRevokeComponent(m_componentID);
                }
                m_componentID = 0;
            }

            base.Dispose(disposing);
        }


        #region IOleComponent Members

        public int FDoIdle(uint grfidlef)
        {
            bool bPeriodic = (grfidlef & (uint)_OLEIDLEF.oleidlefPeriodic) != 0;
            // Use typeof(MyLanguageService) because we need to
            // reference the GUID for our language service.
            LanguageService service = GetService(typeof(MyLanguageService))
                                      as LanguageService;
            if (service != null)
            {
                service.OnIdle(bPeriodic);
            }
            return 0;
        }

        public int FContinueMessageLoop(uint uReason,
                                        IntPtr pvLoopData,
                                        MSG[] pMsgPeeked)
        {
            return 1;
        }

        public int FPreTranslateMessage(MSG[] pMsg)
        {
            return 0;
        }

        public int FQueryTerminate(int fPromptUser)
        {
            return 1;
        }

        public int FReserved1(uint dwReserved,
                              uint message,
                              IntPtr wParam,
                              IntPtr lParam)
        {
            return 1;
        }

        public IntPtr HwndGetWindow(uint dwWhich, uint dwReserved)
        {
            return IntPtr.Zero;
        }

        public void OnActivationChange(IOleComponent pic,
                                       int fSameComponent,
                                       OLECRINFO[] pcrinfo,
                                       int fHostIsActivating,
                                       OLECHOSTINFO[] pchostinfo,
                                       uint dwReserved)
        {
        }

        public void OnAppActivate(int fActive, uint dwOtherThreadID)
        {
        }

        public void OnEnterState(uint uStateID, int fEnter)
        {
        }

        public void OnLoseActivation()
        {
        }

        public void Terminate()
        {
        }

        #endregion
    }
}

See Also

Concepts

Managed-Code Language Services with the MPF

Managed Language Service Overview (Managed Package Framework)