Registering a Legacy Language Service
Note
This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here
In the managed package framework (MPF), the language service is proffered by a VSPackage (see VSPackages) and is registered with Visual Studio by adding registry keys and entries. This registration process is done in partly during installation and partly at runtime.
Register the Language Service by Using Attributes
The following attributes are used to register a language service.
ProvideLanguageEditorOptionPageAttribute
These attributes are explained below
ProvideServiceAttribute
This attribute registers your language service as a service.
Example
using Microsoft.VisualStudio.Shell;
namespace TestLanguagePackage
{
[ProvideServiceAttribute(typeof(TestLanguageService),
ServiceName = "Test Language Service")]
public class TestLanguagePackage : Package
{
}
}
ProvideLanguageServiceAttribute
This attribute registers your language service specifically as a language service. It allows you to set options that specify the features that your language service offers. The example shows a subset of the options a language service can provide. For the full set of language service options, see ProvideLanguageServiceAttribute.
Example
using Microsoft.VisualStudio.Shell;
namespace TestLanguagePackage
{
[ProvideLanguageServiceAttribute(typeof(TestLanguageService),
"Test 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 TestLanguagePackage : Package
{
}
}
ProvideLanguageExtensionAttribute
This attribute associates your language service with a file extension. 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.
Example
using Microsoft.VisualStudio.Shell;
namespace TestLanguagePackage
{
[ProvideLanguageExtensionAttribute(typeof(TestLanguageService),
".Testext")]
public class TestLanguagePackage : 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 by the editor when a code snippet is inserted into the source file.
Example
using Microsoft.VisualStudio.Shell;
namespace TestLanguagePackage
{
[ProvideLanguageCodeExpansionAttribute(
typeof(TestLanguageService),
"Test Language", // Name of language used as registry key.
106, // Resource ID of localized name of language service.
"testlanguage", // language key used in snippet templates.
@"%InstallRoot%\Test Language\SnippetsIndex.xml", // Path to snippets index
SearchPaths = @"%InstallRoot%\Test Language\Snippets\%LCID%\Snippets\;" +
@"%TestDocs%\Code Snippets\Test Language\Test Code Snippets"
)]
public class TestLanguagePackage : Package
{
}
}
ProvideLanguageEditorOptionPageAttribute
This attribute registers a property page to be displayed in the 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.
Example
This example shows two property pages, Options and Indenting, and one node that contains the second property page.
using Microsoft.VisualStudio.Shell;
namespace TestLanguagePackage
{
[ProvideLanguageEditorOptionPageAttribute(
"Test 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
)]
[ProvideLanguageEditorOptionPageAttribute(
"Test Language", // Registry key name for language
"Advanced", // Registry key name for node
"#243", // Localized name of node
)]
[ProvideLanguageEditorOptionPageAttribute(
"Test 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 TestLanguagePackage : Package
{
}
}
Proffer the Language Service at Runtime
When your language package is loaded, you must tell Visual Studio that your language service is ready. You do this by proffering the service. 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;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
namespace TestLanguagePackage
{
[Microsoft.VisualStudio.Shell.ProvideService(typeof(TestLanguageService))]
[Microsoft.VisualStudio.Shell.ProvideLanguageExtension(typeof(TestLanguageService), ".testext")]
[Microsoft.VisualStudio.Shell.ProvideLanguageService(typeof(TestLanguageService), "Test Language", 0,
AutoOutlining = true,
EnableCommenting = true,
MatchBraces = true,
ShowMatchingBrace = true)]
[Guid("00000000-0000-0000-0000-00000000000")] //provide a unique GUID for the package
public class TestLanguagePackage : Package, IOleComponent
{
private uint m_componentID;
protected override void Initialize()
{
base.Initialize(); // required
// Proffer the service.
IServiceContainer serviceContainer = this as IServiceContainer;
TestLanguageService langService = new TestLanguageService();
langService.SetSite(this);
serviceContainer.AddService(typeof(TestLanguageService),
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(TestLanguageService) because we need to
// reference the GUID for our language service.
LanguageService service = GetService(typeof(TestLanguageService))
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
}
}