{"id":2083,"date":"2010-05-16T16:00:00","date_gmt":"2010-05-16T16:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/2010\/05\/16\/three-new-managed-package-framework-features-for-visual-studio-2010\/"},"modified":"2022-10-13T14:34:37","modified_gmt":"2022-10-13T21:34:37","slug":"three-new-managed-package-framework-features-for-visual-studio-2010","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/three-new-managed-package-framework-features-for-visual-studio-2010\/","title":{"rendered":"Three New Managed Package Framework features for Visual Studio 2010"},"content":{"rendered":"<p>This post describes three new features that have been added to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb164709(VS.100).aspx\">Managed Package Framework<\/a> (MPF) version 10.0 in Visual Studio 2010. These features are available to anyone developing extensions in managed code for Visual Studio 2010. To get started building extensions for Visual Studio, start by visiting the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/vsx\/default.aspx\">Visual Studio Extensibility Developer Center<\/a> on MSDN and then go and download the <a href=\"http:\/\/www.microsoft.com\/downloads\/details.aspx?familyid=47305CF4-2BEA-43C0-91CD-1B853602DCC5\">Visual Studio 2010 SDK<\/a>.<\/p>\n<p>To use these features, your extension must reference the assembly Microsoft.VisualStudio.Shell.10.0.<\/p>\n<h3>1. <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.serviceprovider.globalprovider(VS.100).aspx\">ServiceProvider.GlobalProvider<\/a><\/h3>\n<p>This new static property on the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.serviceprovider(VS.100).aspx\">ServiceProvider<\/a> class allows access to the global service provider from any code, <strong>as long as it is called from the main UI thread<\/strong>. This property is closely related to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.package.getglobalservice(VS.100).aspx\">Package.GetGlobalService<\/a> static method which was available in previous versions of the MPF. The problem with Package.GetGlobalService was that it would fail if a package had not yet been initialized. This led to subtle ordering bugs in code that used the MPF libraries without initializing a package of their own. Sometimes they would work only because another package had already initialized the global ServiceProvider on their behalf. If that <em>other <\/em>package was uninstalled, or perhaps moved to a different version of the MPF, that static would no longer be initialized causing Package.GetGlobalService to fail.<\/p>\n<p>Now, in MPF 10, you can call ServiceProvider.GlobalProvider at any time as long as you are calling from the UI thread. For compatibility, this mechanism will still use the ServiceProvider created by the first <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.package(VS.100).aspx\">Package<\/a> to be <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb685879(VS.100).aspx\">sited<\/a> but, in the case where no Package has yet been <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.package.initialize(VS.100).aspx\">initialized<\/a>, MPF 10.0 now has the ability to obtain the global provider from the registered <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms693324(VS.85).aspx\">COM message filter<\/a>. Package.GetGlobalService() is also hooked up to this new mechanism.<\/p>\n<h3>2. <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.activitylog(VS.100).aspx\">ActivityLog<\/a><\/h3>\n<p>The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms241272(VS.100).aspx\">activity log<\/a> is a feature first introduced in Visual Studio 2005 for diagnosing package load failures. In Visual Studio 2010, we started to log a few <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/troubleshooting-extensions-with-the-activity-log\/\">more things<\/a> to the activity log and would like to promote it as the service for all extensions to use for low-frequency diagnostics. To that end, we created a very simple-to-use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.activitylog(VS.100).aspx\">ActivityLog<\/a> class. It\u2019s small enough to post the public interface here.<\/p>\n<blockquote>\n<pre class=\"code\"><span style=\"font-family: Consolas; font-size: small;\">\/\/\/ &lt;summary&gt;\r\n\/\/\/ <\/span><span style=\"font-family: Consolas; font-size: small;\">Class which provides convenient managed methods for logging messages to the IVsActivityLog.\r\n<\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/\/ &lt;\/summary&gt;\r\npublic static class <\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">ActivityLog\r\n{\r\n    <\/span><\/span><span style=\"font-family: Consolas; font-size: small;\">\/\/\/ &lt;summary&gt;\r\n    \/\/\/ <\/span><span style=\"font-family: Consolas; font-size: small;\">Gets the path to the activity log for the current application.\r\n    <\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/\/ &lt;\/summary&gt;\r\n    public static string LogFilePath { get; }\r\n    <\/span><\/span><span style=\"font-family: Consolas; font-size: small;\">\/\/\/ &lt;summary&gt;\r\n    \/\/\/ <\/span><span style=\"font-family: Consolas; font-size: small;\">Logs an error message in the activity log with the given source.\r\n    <\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=\"source\"&gt;A name associated with the source contributing the message.<\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=\"message\"&gt;The message to be written to the activity log.<\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">&lt;\/param&gt;\r\n    public static void LogError(string source, string message);\r\n    <\/span><\/span><span style=\"font-family: Consolas; font-size: small;\">\/\/\/ &lt;summary&gt;\r\n    \/\/\/ <\/span><span style=\"font-family: Consolas; font-size: small;\">Logs a warning message in the activity log with the given source.\r\n    <\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=\"source\"&gt;A name associated with the source contributing the message.<\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=\"message\"&gt;The message to be written to the activity log.<\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">&lt;\/param&gt;\r\n    public static void LogWarning(string source, string message);\r\n    <\/span><\/span><span style=\"font-family: Consolas; font-size: small;\">\/\/\/ &lt;summary&gt;\r\n    \/\/\/ <\/span><span style=\"font-family: Consolas; font-size: small;\">Logs an information message in the activity log with the given source.\r\n    <\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;param name=\"source\"&gt;A name associated with the source contributing the message.<\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">&lt;\/param&gt;\r\n    \/\/\/ &lt;param name=\"message\"&gt;The message to be written to the activity log.<\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">&lt;\/param&gt;\r\n    public static void LogInformation(string source, string message);\r\n}<\/span><\/span><\/pre>\n<\/blockquote>\n<p>All public methods and properties on the class are static which makes it incredibly easy to use from your own code. e.g.:<\/p>\n<blockquote><p>ActivityLog.LogInformation(&#8220;ACME Widget Package&#8221;, &#8220;The widget is disconnected&#8221;);<\/p><\/blockquote>\n<p>Internally, of course, ActivityLog uses ServiceProvider.GlobalProvider to locate the global service provider.<\/p>\n<p>I have to give credit and thanks for this idea to <a href=\"http:\/\/friendfeed.com\/istvan-novak\">Istv\u00e1n Nov\u00e1k<\/a>, one of our <a href=\"http:\/\/mvp.support.microsoft.com\/\">MVPs<\/a>, who regularly visits us in Redmond to attend and also present at our Visual Studio developer clinics. Istv\u00e1n has developed a set of managed classes called \u201c<a href=\"http:\/\/vsxtra.codeplex.com\/\">VSXtra<\/a>\u201d for easing the development of managed packages by providing a useful set of helper classes. This new class was inspired by a discussion I had with him at the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/vstudio\/cc512752.aspx\">Developer Tools Summit<\/a> last October and was incorporated into MPF 10.0 with his permission.<\/p>\n<h3>3. <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.threadhelper(VS.100).aspx\">ThreadHelper<\/a><\/h3>\n<p>The ThreadHelper class allows managed code running on any thread to run operations on the UI thread. This may be necessary if you are calling into a component that is not thread-safe and must be called on the UI thread. This mechanism is preferred over other existing techniques like <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.threading.dispatcher.invoke(VS.100).aspx\">Dispatcher.Invoke<\/a> from WPF or <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/zyzhdc6b(VS.100).aspx\">Control.Invoke<\/a> from Windows Forms because neither of these is \u201c<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa378651(VS.85).aspx\">RPC<\/a> aware\u201d and using them may result in deadlocks in some scenarios. As you may know, Visual Studio is heavily rooted in COM and RPC is the primary mechanism used by components to communicate across threads or processes.<\/p>\n<p>Under the covers, ThreadHelper makes a private cross-apartment COM call to the UI thread where the \u2018invokable\u2019 operation completes. By using a genuine COM call, we maintain what\u2019s known as \u201c<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms693805\">logical thread identity<\/a>\u201d throughout the call. If the call to the UI thread is itself part of a cross-thread COM call, then it will be recognized as part of the same call (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms680554(VS.85).aspx\">CALLTYPE_NESTED<\/a>) and not a new top-level call. Both WPF\u2019s and Windows Forms\u2019 invoke operations post private messages to the UI thread and this breaks the chain of logical thread identity.<\/p>\n<p>ThreadHelper really has only one interesting method, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee197798.aspx\">Invoke<\/a>, although it takes two forms:<\/p>\n<blockquote>\n<pre class=\"code\"><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">public void Invoke(Action action);\r\npublic TResult Invoke&lt;TResult&gt;(Func&lt;TResult&gt; method);<\/span><\/span><\/pre>\n<\/blockquote>\n<p>The argument passed to Invoke is a delegate for the operation you want to perform on the UI thread. If the caller is already on the UI thread, then the delegate is invoked directly. If the operation throws an exception, then the exception is re-raised on the calling thread.<\/p>\n<p>Using ThreadHelper in your own code is straightforward, but note that ThreadHelper itself is abstract to allow for advanced extensibility. Most of the time, you\u2019ll use the general purpose implementation accessed through the static property <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.visualstudio.shell.threadhelper.generic(v=VS.100).aspx\">ThreadHelper.Generic<\/a>. Here\u2019s an example:<\/p>\n<blockquote>\n<pre class=\"code\"><span style=\"font-family: Consolas; font-size: small;\">public class <\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">MyComponent\r\n{\r\n    public string Name\r\n    {\r\n        <\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">get\r\n        {\r\n            <\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/ The Name property may be accessed from any thread, but the\r\n            \/\/ implementation requires that the call comes in on the UI thread.\r\n            return <span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">ThreadHelper<\/span><\/span>.Generic.Invoke(() =&gt; GetName());\r\n        }\r\n    }\r\n    <\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/ Must be called on the UI thread\r\n    private string GetName()\r\n    {\r\n        <\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/ ...\r\n    }\r\n    <\/span><\/span><span style=\"font-size: small;\"><span style=\"font-family: Consolas;\">\/\/ ...\r\n}<\/span><\/span><\/pre>\n<\/blockquote>\n<h3>Conclusion<\/h3>\n<p>I hope you\u2019ll find these three new features useful when developing your own managed extensions to Visual Studio 2010. As always, please feel free to use the comment stream to ask questions.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/clip_image002_2.jpg\"><em><img decoding=\"async\" title=\"clip_image002\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2010\/05\/clip_image002_thumb.jpg\" alt=\"clip_image002\" width=\"101\" height=\"101\" align=\"left\" border=\"0\" \/><\/em><\/a><\/p>\n<p><strong>Paul Harrington<\/strong> \u2013 Principal Developer, Visual Studio Platform Team.\n<strong>Biography: <\/strong>Paul has worked on every version of Visual Studio .Net to date. Prior to joining the Visual Studio team in 2000, Paul spent six years working on mapping and trip planning software for what is today known as Bing Maps. For Visual Studio 2010, Paul designed and helped write the code that enabled the Visual Studio Shell team to move from a native, Windows 32-based implementation to a modern, fully managed presentation layer based on the Windows Presentation Foundation (WPF). Paul holds a master\u2019s degree from the University of Cambridge, England and lives with his wife and two cats in Seattle, Washington.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post describes three new features that have been added to the Managed Package Framework (MPF) version 10.0 in Visual Studio 2010. These features are available to anyone developing extensions in managed code for Visual Studio 2010. To get started building extensions for Visual Studio, start by visiting the Visual Studio Extensibility Developer Center on [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":255385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155],"tags":[294,13],"class_list":["post-2083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","tag-extensions","tag-visual-studio-2010"],"acf":[],"blog_post_summary":"<p>This post describes three new features that have been added to the Managed Package Framework (MPF) version 10.0 in Visual Studio 2010. These features are available to anyone developing extensions in managed code for Visual Studio 2010. To get started building extensions for Visual Studio, start by visiting the Visual Studio Extensibility Developer Center on [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/2083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=2083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/2083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/255385"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=2083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=2083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=2083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}