<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Office Development with Visual Studio : McLean Schofield</title><link>http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx</link><description>Tags: McLean Schofield</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Create an Excel Shortcut Menu That Writes Selected Values to a Text File (Harry Miller)</title><link>http://blogs.msdn.com/vsto/archive/2008/08/22/create-an-excel-shortcut-menu-that-writes-selected-values-to-a-text-file-harry-miller.aspx</link><pubDate>Fri, 22 Aug 2008 23:14:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8888730</guid><dc:creator>VSTO Team</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/vsto/comments/8888730.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vsto/commentrss.aspx?PostID=8888730</wfw:commentRss><description>&lt;p&gt;It doesn't take much code to add a command to a shortcut menu in Excel, but the menu objects have strange names so it's not intuitive, to me at least. The trickiest part is just sorting out how it's supposed to work, because it seems like it should be different from adding buttons to toolbars, but it really looks like that's what you're doing.&lt;/p&gt;  &lt;p&gt;You can watch the video and make me happy, or you can just jump to the code example that's all given a little lower down. Thanks to McLean Schofield, programmer/writer and 3-star forum answer person, for this code example!&lt;/p&gt;  &lt;p&gt;Duration: 3 minutes, 50 seconds.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:01d81165-79b0-49d5-baf0-2678a43cbf83" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;div id="3e6cb28d-5797-43d6-b2c8-746d5c8505b8" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://video.msn.com/video.aspx?vid=a927908c-e0dc-4a9e-8b59-faeeabe0cbbc&amp;amp;from=writer" target="_new"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/CreateanExcelShortcutMenuThatWritesSelec_B7C0/videofece4865a6bc.jpg" galleryimg="no" onload="var downlevelDiv = document.getElementById('3e6cb28d-5797-43d6-b2c8-746d5c8505b8'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;embed src=\&amp;quot;http://images.video.msn.com/flash/soapbox1_1.swf\&amp;quot; quality=\&amp;quot;high\&amp;quot; width=\&amp;quot;432\&amp;quot; height=\&amp;quot;364\&amp;quot; wmode=\&amp;quot;transparent\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; pluginspage=\&amp;quot;http://macromedia.com/go/getflashplayer\&amp;quot; flashvars=\&amp;quot;c=v&amp;amp;v=a927908c-e0dc-4a9e-8b59-faeeabe0cbbc&amp;amp;from=writer\&amp;quot; &amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Public Class ThisAddIn &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Private WithEvents writeToText As Office.CommandBarButton   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Private selectedCells As Excel.Range &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Private Sub ThisAddIn_Startup(ByVal sender _   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; As Object, ByVal e As System.EventArgs) Handles Me.Startup &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DefineShortcutMenu()   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End Sub &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Private Sub DefineShortcutMenu() &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim menuItem As Office.MsoControlType = Office.MsoControlType.msoControlButton   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; writeToText = Application.CommandBars(&amp;quot;Cell&amp;quot;).Controls.Add(Type:=menuItem, _    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Before:=1, Temporary:=True) &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; writeToText.Style = Office.MsoButtonStyle.msoButtonCaption   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; writeToText.Caption = &amp;quot;Write to a Text File&amp;quot;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; writeToText.Tag = &amp;quot;0&amp;quot;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End Sub &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Private Sub Application_SheetBeforeRightClick(ByVal Sh _   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; As Object, ByVal Target As Microsoft.Office.Interop.Excel.Range, _    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ByRef Cancel As Boolean) Handles Application.SheetBeforeRightClick &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; selectedCells = Target   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End Sub &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Private Sub writeToText_Click(ByVal Ctrl As Office.CommandBarButton, _   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ByRef CancelDefault As Boolean) Handles writeToText.Click &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Try   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim currentDateTime As System.DateTime = _    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; System.DateTime.Now    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim dateStamp As String = _    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; currentDateTime.ToString(&amp;quot;dMMMMyyyy_hh.mm.ss&amp;quot;) &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim fileName As String = System.Environment.GetFolderPath( _   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Environment.SpecialFolder.MyDocuments) &amp;amp; &amp;quot;\\&amp;quot; &amp;amp; _    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; dateStamp &amp;amp; &amp;quot;.txt&amp;quot;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim sw As System.IO.StreamWriter = New System.IO.StreamWriter(fileName) &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; For Each cell As Excel.Range In selectedCells.Cells   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If cell.Value2 IsNot Nothing Then    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; sw.WriteLine(cell.Value2.ToString())    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Next    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; sw.Close()    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Catch ex As Exception    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; System.Windows.Forms.MessageBox.Show(ex.Message)    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End Try &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; End Sub&lt;/p&gt;  &lt;p&gt;End Class&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8888730" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vsto/archive/tags/Command+bars/default.aspx">Command bars</category><category domain="http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx">McLean Schofield</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Harry+Miller/default.aspx">Harry Miller</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Excel+2007/default.aspx">Excel 2007</category><category domain="http://blogs.msdn.com/vsto/archive/tags/VB/default.aspx">VB</category><category domain="http://blogs.msdn.com/vsto/archive/tags/video/default.aspx">video</category></item><item><title>WPF in Office Solutions (Harry Miller)</title><link>http://blogs.msdn.com/vsto/archive/2008/06/25/wpf-in-office-solutions-harry-miller.aspx</link><pubDate>Wed, 25 Jun 2008 17:01:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8652198</guid><dc:creator>VSTO Team</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/vsto/comments/8652198.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vsto/commentrss.aspx?PostID=8652198</wfw:commentRss><description>&lt;p&gt;A few months ago, Andrew Whitechapel wrote an article and sample application that demonstrates combining the native capabilities of an Office client application with the UI capabilities of WPF. Behind the UI, the application is connected to remote data and services via WCF and uses the RAD features of LINQ to manipulate that data.&lt;/p&gt;  &lt;p&gt;Some related questions have come up in the forum recently, so McLean Schofield took the sample application and made a short video overview of the WPF control part. You can find the full explanation and get the code from these articles:&lt;/p&gt;  &lt;p&gt;Build Office-Based Solutions Using WPF, WCF, And LINQ - MSDN Magazine article by Andrew Whitechapel&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163292.aspx"&gt;http://msdn.microsoft.com/en-us/magazine/cc163292.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Andrew Whitechapel's blog post, which has a link to updated code&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/andreww/archive/2007/11/26/vsto-wpf-wcf-linq-msdn-article.aspx"&gt;http://blogs.msdn.com/andreww/archive/2007/11/26/vsto-wpf-wcf-linq-msdn-article.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Video duration: 4 minutes, 23 seconds&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:25427c9c-9946-4a3b-95ab-fff439f32c7e" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;div id="cbc166d7-35a3-4897-a2b3-e2de8e99255c" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://video.msn.com/video.aspx?vid=a8ae10a5-8977-4bab-b1b7-9b31fc60d67b&amp;amp;from=writer" target="_new"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/WPFinOfficeSolutions_61DB/video0ba090bf1982.jpg" galleryimg="no" onload="var downlevelDiv = document.getElementById('cbc166d7-35a3-4897-a2b3-e2de8e99255c'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;embed src=\&amp;quot;http://images.video.msn.com/flash/soapbox1_1.swf\&amp;quot; quality=\&amp;quot;high\&amp;quot; width=\&amp;quot;432\&amp;quot; height=\&amp;quot;364\&amp;quot; wmode=\&amp;quot;transparent\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; pluginspage=\&amp;quot;http://macromedia.com/go/getflashplayer\&amp;quot; flashvars=\&amp;quot;c=v&amp;amp;v=a8ae10a5-8977-4bab-b1b7-9b31fc60d67b&amp;amp;from=writer\&amp;quot; &amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8652198" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx">McLean Schofield</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Harry+Miller/default.aspx">Harry Miller</category><category domain="http://blogs.msdn.com/vsto/archive/tags/sample/default.aspx">sample</category><category domain="http://blogs.msdn.com/vsto/archive/tags/video/default.aspx">video</category><category domain="http://blogs.msdn.com/vsto/archive/tags/WPF/default.aspx">WPF</category></item><item><title>Calling Into A VSTO Add-in From a COM Smart Tag (McLean Schofield)</title><link>http://blogs.msdn.com/vsto/archive/2008/05/07/calling-into-a-vsto-add-in-from-a-com-smart-tag.aspx</link><pubDate>Wed, 07 May 2008 23:38:31 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8466997</guid><dc:creator>VSTO Team</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/vsto/comments/8466997.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vsto/commentrss.aspx?PostID=8466997</wfw:commentRss><description>&lt;p&gt;My &lt;a href="http://blogs.msdn.com/vsto/archive/2008/05/02/understanding-vsto-smart-tags-and-com-smart-tags-mclean-schofield.aspx"&gt;last post&lt;/a&gt; explained some of the differences between VSTO smart tags (that is, smart tags that you implement in a document-level solution for Word or Excel by using VSTO) and COM smart tags (that is, smart tags that you create by implementing COM interfaces provided by the smart tag SDK). If you are using VSTO to create application-level add-ins for Word or Excel, or add-ins for other applications that support smart tags, such as PowerPoint and Outlook, then you must use the smart tag SDK if you want to also create smart tags for these applications. The general recommendation is to create your smart tags in a separate assembly (or unmanaged DLL, if you wish).&lt;/p&gt; &lt;p&gt;At the end of the post, I mentioned that if you go this route, you can still call into the VSTO add-in from the COM smart tag. Any technology that enables you to communicate between application domains, such as &lt;a href="http://msdn.microsoft.com/en-us/library/72x4h507.aspx"&gt;.NET remoting&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/library/ms735119.aspx"&gt;Windows Communication Foundation&lt;/a&gt;, should work, with varying degrees of complexity. However, the easiest way to do use built-in APIs provided by VSTO and Office to expose an object in your add-in to the smart tag, and then to call into this object from the smart tag. &lt;/p&gt; &lt;h3&gt;Exposing an Object in Your Add-in to the Smart Tag&lt;/h3&gt; &lt;p&gt;Starting in VSTO 2005 SE, add-ins have been able to expose functionality to other Office solutions by overriding the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.tools.addin.requestcomaddinautomationservice.aspx"&gt;RequestComAddInAutomationService&lt;/a&gt; method. When your add-in is loaded, the VSTO runtime calls this method to give you an opportunity to return an object that want other Office solutions to use. For example, if your add-in can display a custom task pane that enables end users to navigate data, you can expose this feature to other solutions by defining a class with a method that displays the task pane, and then returning an instance of this class in your override of &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.tools.addin.requestcomaddinautomationservice.aspx"&gt;RequestComAddInAutomationService&lt;/a&gt;. &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;Side-bar&lt;/em&gt;: COM add-ins that implement the &lt;a href="http://msdn.microsoft.com/en-us/library/extensibility.idtextensibility2.aspx"&gt;IDTExtensibility2&lt;/a&gt; interface directly can do the same thing. In the implementation of the &lt;a href="http://msdn.microsoft.com/en-us/library/extensibility.idtextensibility2.onconnection.aspx"&gt;OnConnection&lt;/a&gt; method, the add-in receives an object that represents the application's view of the add-in as the &lt;em&gt;AddInInst&lt;/em&gt; parameter. Although this parameter is typed as an object, for Office add-ins, this object is really a &lt;a href="http://msdn.microsoft.com/en-us/library/aa432084.aspx"&gt;COMAddIn&lt;/a&gt;. Inside the &lt;a href="http://msdn.microsoft.com/en-us/library/extensibility.idtextensibility2.onconnection.aspx"&gt;OnConnection&lt;/a&gt; method, the add-in can set the &lt;a href="http://msdn.microsoft.com/en-us/library/aa432315.aspx"&gt;COMAddIn.Object&lt;/a&gt; property to an object it wants to expose. When you override &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.tools.addin.requestcomaddinautomationservice.aspx"&gt;RequestComAddInAutomationService&lt;/a&gt; in a VSTO add-in, fundamentally the same thing is going on under the covers, but this is all abstracted away from view. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The following code example demonstrates a simple implementation of &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.tools.addin.requestcomaddinautomationservice.aspx"&gt;RequestComAddInAutomationService&lt;/a&gt;. This assumes that my VSTO add-in defines a class called &lt;em&gt;AddInUtilities&lt;/em&gt;, which I want other solutions to be able to use.&lt;/p&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Private utilities As AddInUtilities &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier" size="2"&gt;Protected Overrides Function RequestComAddInAutomationService() As Object&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;If utilities Is Nothing Then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;utilities = New AddInUtilities()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End If&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Return utilities&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Function&lt;/font&gt;&lt;/p&gt; &lt;p&gt;It is important to understand that you can't return just any object. Your object must be in an instance of a class that is visible to COM, and that exposes the &lt;a href="http://msdn.microsoft.com/en-us/library/ms221608(VS.85).aspx"&gt;IDispatch&lt;/a&gt; interface. One way to meet these requirements is to first define a COM-visible interface that exposes &lt;a href="http://msdn.microsoft.com/en-us/library/ms221608(VS.85).aspx"&gt;IDispatch&lt;/a&gt;. You should define this interface in its own assembly (for example, a class library project), so that the VSTO add-in and the smart tag assembly can both reference the same interface declaration. The following example demonstrates a simple &lt;em&gt;IAddInUtilities&lt;/em&gt; interface that defines a method called &lt;em&gt;DisplayData&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier" size="2"&gt;&amp;lt;System.Runtime.InteropServices.ComVisibleAttribute(True)&amp;gt; _&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&amp;lt;System.Runtime.InteropServices.InterfaceType( _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;ComInterfaceType.InterfaceIsIDispatch)&amp;gt; _&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Public Interface IAddInUtilities&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Sub DisplayData()&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Interface&lt;/font&gt;  &lt;p&gt;Then, in your VSTO add-in that references the assembly that declares &lt;em&gt;IAddInUtilities&lt;/em&gt;, you can define a COM-visible class that implements the &lt;em&gt;IAddInUtilities&lt;/em&gt; interface. The actual code in the &lt;em&gt;DisplayData&lt;/em&gt; implementation isn't important for this discussion, so I'll leave it out for clarity.&lt;/p&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier" size="2"&gt;&amp;lt;System.Runtime.InteropServices.ComVisibleAttribute(True)&amp;gt; _&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&amp;lt;System.Runtime.InteropServices.ClassInterface( _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;System.Runtime.InteropServices.ClassInterfaceType.None)&amp;gt; _&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Public Class AddInUtilities&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Implements IAddInUtilities &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Public Sub DisplayData() Implements IAddInUtilities.DisplayData &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;' Do stuff here. &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Sub&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Class&lt;/font&gt; &lt;p&gt;For more specific details about the requirements for the object you return in &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.tools.addin.requestcomaddinautomationservice.aspx"&gt;RequestComAddInAutomationService&lt;/a&gt;, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb608621.aspx"&gt;Calling Code in Application-Level Add-ins from Other Office Solutions&lt;/a&gt;. For a walkthrough that demonstrates how to expose an object in a VSTO add-in and then call into the object from VBA code in an Excel workbook, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb608614.aspx"&gt;Walkthrough: Calling Code in an Application-Level Add-in from VBA&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Accessing the Object From a COM Smart Tag&lt;/h3&gt; &lt;p&gt;When you create a COM smart tag, you must implement the &lt;a href="http://msdn.microsoft.com/en-us/library/aa207016(office.11).aspx"&gt;ISmartTagRecognizer&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/aa206982(office.11).aspx"&gt;ISmartTagAction&lt;/a&gt; interfaces. Of these, &lt;a href="http://msdn.microsoft.com/en-us/library/aa206982(office.11).aspx"&gt;ISmartTagAction&lt;/a&gt; defines a specific action that the end user can select when they click your smart tag. This is a likely place to want to call into your VSTO add-in. The question is, how do you do this?&lt;/p&gt; &lt;p&gt;When the user clicks the icon to run an action, your implementation of the &lt;a href="http://msdn.microsoft.com/en-us/library/aa206924(office.11).aspx"&gt;ISmartTagAction.InvokeVerb&lt;/a&gt; method contains the code that you want to run. The &lt;em&gt;Target&lt;/em&gt; parameter of this method is an application-specific object that represents the context in which the smart tag appears. For example, in Excel, the &lt;em&gt;Target&lt;/em&gt; parameter is a &lt;a href="http://msdn.microsoft.com/en-us/library/bb178282.aspx"&gt;Range&lt;/a&gt; that identifies the cell that the smart tag was attached to.&lt;/p&gt; &lt;p&gt;In your implementation of &lt;a href="http://msdn.microsoft.com/en-us/library/aa206924(office.11).aspx"&gt;ISmartTagAction.InvokeVerb&lt;/a&gt;, you can cast the &lt;em&gt;Target&lt;/em&gt; parameter to the appropriate object in the object model of the application. From there, you can easily traverse the application's object model to get the Application object, then the &lt;a href="http://msdn.microsoft.com/en-us/library/aa432084.aspx"&gt;COMAddIn&lt;/a&gt; object for your VSTO add-in, and then finally the &lt;a href="http://msdn.microsoft.com/en-us/library/aa432315.aspx"&gt;Object&lt;/a&gt; property that contains the object you exposed in the add-in.&lt;/p&gt; &lt;p&gt;The following example demonstrates a simple implementation of &lt;a href="http://msdn.microsoft.com/en-us/library/aa206924(office.11).aspx"&gt;InvokeVerb&lt;/a&gt;. If the recognized term is &lt;em&gt;sale&lt;/em&gt;, then this method calls a helper method named &lt;em&gt;CallAddIn&lt;/em&gt;, and passes the &lt;em&gt;Target&lt;/em&gt; parameter to this helper method.&lt;/p&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier" size="2"&gt;Public Sub InvokeVerb(ByVal VerbID As Integer, _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;ByVal AppplicationName As String, _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;ByVal Target As Object, ByVal Properties As ISmartTagProperties, _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;ByVal Text As String, ByVal Xml As String) _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Implements ISmartTagAction.InvokeVerb &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;If String.Compare("sale", Text, True) = 0 Then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Select Case VerbID&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Case 1&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;CallAddIn(Target)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Select&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End If&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Sub&lt;/font&gt;  &lt;p&gt;Here is the definition of the &lt;em&gt;CallAddIn&lt;/em&gt; helper method. &lt;/p&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier" size="2"&gt;Private Sub CallAddIn(ByVal Target As Object)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Dim ExcelApp As Microsoft.Office.Interop.Excel.Application = Nothing &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;If Target IsNot Nothing Then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Dim SmartTagRange As Microsoft.Office.Interop.Excel.Range = _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;TryCast(Target, Microsoft.Office.Interop.Excel.Range) &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;If SmartTagRange IsNot Nothing Then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;ExcelApp = SmartTagRange.Application&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End If&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End If &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;If ExcelApp IsNot Nothing Then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Dim AddIn As Microsoft.Office.Core.COMAddIn = ExcelApp.COMAddIns( _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;"ExcelSmartTagInteropDemo")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Dim Utilities As AddInInterfaces.IAddInUtilities = _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;TryCast(AddIn.Object, AddInInterfaces.IAddInUtilities) &lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;If Utilities IsNot Nothing Then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;Utilities.DisplayData()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End If&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End If&lt;br&gt;&lt;font face="Courier" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;End Sub&lt;/font&gt; &lt;p&gt;&lt;font face="Courier" size="2"&gt;&lt;/font&gt; &lt;p&gt;This method tries to cast the &lt;em&gt;Target&lt;/em&gt; parameter to an Excel &lt;a href="http://msdn.microsoft.com/en-us/library/bb178282.aspx"&gt;Range&lt;/a&gt;. If successful, the method gets the Excel &lt;a href="http://msdn.microsoft.com/en-us/library/bb210077.aspx"&gt;Application&lt;/a&gt; object, and then uses the &lt;a href="http://msdn.microsoft.com/en-us/library/bb177376.aspx"&gt;COMAddIns&lt;/a&gt; property to get the &lt;a href="http://msdn.microsoft.com/en-us/library/aa432084.aspx"&gt;COMAddIn&lt;/a&gt; that represents a loaded VSTO add-in with the name &lt;em&gt;ExcelSmartTagInteropDemo&lt;/em&gt;. Finally, the method gets the &lt;a href="http://msdn.microsoft.com/en-us/library/aa432315.aspx"&gt;Object&lt;/a&gt; property, tries to cast it to an &lt;em&gt;IAddInUtilities&lt;/em&gt;, and then calls the &lt;em&gt;DisplayData&lt;/em&gt; method implemented by the add-in. This of course assumes that the smart tag assembly references the assembly in which the &lt;em&gt;IAddInUtilities&lt;/em&gt; interface is defined. &lt;p&gt;At run time, when the end user types "sale" in an Excel range and clicks the smart tag action, then the smart tag calls into the &lt;em&gt;DisplayData&lt;/em&gt; method implemented in the VSTO add-in. This all happens by way of COM interop via several built-in APIs in VSTO and Office. &lt;p&gt;-------------------------------------------------- &lt;p&gt;McLean Schofield, programming writer&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8466997" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vsto/archive/tags/VSTO/default.aspx">VSTO</category><category domain="http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx">McLean Schofield</category><category domain="http://blogs.msdn.com/vsto/archive/tags/smart+tags/default.aspx">smart tags</category><category domain="http://blogs.msdn.com/vsto/archive/tags/VB/default.aspx">VB</category></item><item><title>Understanding VSTO Smart Tags and COM Smart Tags (McLean Schofield)</title><link>http://blogs.msdn.com/vsto/archive/2008/05/02/understanding-vsto-smart-tags-and-com-smart-tags-mclean-schofield.aspx</link><pubDate>Fri, 02 May 2008 22:09:33 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8451621</guid><dc:creator>VSTO Team</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/vsto/comments/8451621.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vsto/commentrss.aspx?PostID=8451621</wfw:commentRss><description>&lt;p&gt;The document-level projects for Excel and Word in VSTO (in Visual Studio 2005 and Visual Studio 2008) provide a simple object model that you can use to create smart tags for documents and workbooks. A smart tag is a string that an Office application recognizes in a document. After the application recognizes the string, it displays a small icon next to the text. The user can then click that icon to display a list of actions they can choose from and activate. Typically, the actions are related to in some way to the identified text. For example, you could have a smart tag that recognizes stock symbols; when a user types an uppercase string of letters that matches a known stock symbol, a list of stock-related actions, such as looking up a stock price, could appear.&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/CallingIntoAVSTOAddinFromaCOMSmartTag_8FE7/image_2.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="241" alt="image" src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/CallingIntoAVSTOAddinFromaCOMSmartTag_8FE7/image_thumb.png" width="369" border="0"&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;In most ways, creating smart tags using VSTO is much easier than creating smart tags without VSTO. However, there are some limitations that might prevent you from using VSTO to create smart tags. Even if you cannot use VSTO to create a smart tag, you can still use features in a VSTO add-in from the smart tag. &lt;/p&gt; &lt;p&gt;In this discussion, I'll refer to smart tags created by using VSTO as "VSTO smart tags", and smart tags created without using VSTO as "COM smart tags".&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font size="4"&gt;Creating VSTO Smart Tags&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Creating a VSTO smart tag is relatively straightforward: you create a &lt;em&gt;SmartTag&lt;/em&gt; object that recognizes one or more terms, create one or more &lt;em&gt;Action&lt;/em&gt; objects that define the code that runs when the user clicks your smart tag options, and finally add the &lt;em&gt;SmartTag&lt;/em&gt; object to the &lt;em&gt;VstoSmartTags&lt;/em&gt; property of the &lt;em&gt;ThisDocument&lt;/em&gt; or &lt;em&gt;ThisWorkbook&lt;/em&gt; class in your project.&amp;nbsp; &lt;/p&gt; &lt;p&gt;The following somewhat contrived example demonstrates a simple smart tag in an Excel workbook project. This smart tag recognizes the term "sale", and when clicked, the action displays the address of the cell that contains the recognized term in a message box. This code assumes it is running from the &lt;em&gt;ThisWorkbook&lt;/em&gt; class in the project.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;Private SmartTagExample As Microsoft.Office.Tools.Excel.SmartTag&lt;br&gt;Private WithEvents DisplayAddressAction As Microsoft.Office.Tools.Excel.Action &lt;/font&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;Private Sub AddSmartTag()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SmartTagExample = New Microsoft.Office.Tools.Excel.SmartTag( _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "www.microsoft.com/Demo#DemoSmartTag", "Smart Tag Example")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SmartTagExample.Terms.Add("sale")&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DisplayAddressAction = New Microsoft.Office.Tools.Excel.Action( _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "Display Cell Address") &lt;/font&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ' Add the action to the smart tag.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SmartTagExample.Actions = New Microsoft.Office.Tools.Excel.Action() { _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DisplayAddressAction} &lt;/font&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ' Add the smart tag to the workbook.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Me.VstoSmartTags.Add(SmartTagExample)&lt;br&gt;End Sub &lt;/font&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;Private Sub DisplayAddress_Click(ByVal sender As Object, _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ByVal e As Microsoft.Office.Tools.Excel.ActionEventArgs) _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Handles DisplayAddressAction.Click &lt;/font&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim smartTagAddress As String = e.Range.Address( _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ReferenceStyle:=Excel.XlReferenceStyle.xlA1)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MsgBox("The recognized text '" &amp;amp; e.Text &amp;amp; _&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "' is at range " &amp;amp; smartTagAddress)&lt;br&gt;End Sub&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font face="Courier New" size="2"&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/ms178787.aspx"&gt;How to: Add Smart Tags to Word Documents&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms178788.aspx"&gt;How to: Add Smart Tags to Excel Workbooks&lt;/a&gt; in the VSTO documentation.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font size="4"&gt;Limitations of VSTO Smart Tags&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Although VSTO smart tags are easy to implement, they do have several limitations:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;VSTO smart tags can be used only in document-level projects for Excel and Word. They cannot be used in application-level add-ins for Excel and Word; therefore, you cannot create VSTO smart tags that are recognized in any document or workbook that the user might open (these are also called application-level smart tags).&lt;/li&gt; &lt;li&gt;VSTO smart tags also cannot be used in projects for any other Office application that supports smart tags, such as PowerPoint and Outlook (when composing e-mails with Word as the e-mail editor).&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;If you need to create a smart tag for an application other than Word or Excel, or you need to create an application-level smart tag for Word or Excel, you must create a COM smart tag. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font size="4"&gt;Creating COM Smart Tags&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;To create a COM smart tag, use the &lt;a href="http://msdn.microsoft.com/en-us/library/aa169576(office.11).aspx"&gt;Smart Tag SDK&lt;/a&gt; to create a managed (or unmanaged, if you prefer) DLL that implements the &lt;a href="http://msdn.microsoft.com/en-us/library/aa207016(office.11).aspx"&gt;ISmartTagRecognizer&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/aa206982(office.11).aspx"&gt;ISmartTagAction&lt;/a&gt; COM interfaces at a minimum, and optionally other interfaces, depending on the features you want to provide. This requires familiarity with COM programming, and that you implement all of the properties and methods of these interfaces, even those you don't intend to use. The DLL must also be registered on end user computers, as described in the Smart Tag SDK. &lt;/p&gt; &lt;h4&gt;&lt;strong&gt;&lt;font size="4"&gt;Implementing a COM Smart Tag in a VSTO Add-In&lt;/font&gt;&lt;/strong&gt;&lt;/h4&gt; &lt;p&gt;At this point, you might be wondering whether you could implement a COM smart tag in a VSTO add-in, since a VSTO add-in is a managed assembly, and you can implement COM interfaces in managed code. &lt;/p&gt; &lt;p&gt;You &lt;em&gt;could&lt;/em&gt;, but you probably don't want to. The reason for this is that add-ins and smart tag DLLs have entirely different discovery and load mechanisms in Office: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Office applications discover smart tag DLLs under the &lt;strong&gt;HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag&lt;/strong&gt; registry key, and then call into the smart tag DLL using only the smart tag-specific interfaces (&lt;a href="http://msdn.microsoft.com/en-us/library/aa207016(office.11).aspx"&gt;ISmartTagRecognizer&lt;/a&gt;, etc.). &lt;/li&gt; &lt;li&gt;On the other hand, Office applications discover add-in DLLs under &lt;a href="http://msdn.microsoft.com/en-us/library/bb386106.aspx"&gt;an entirely different (and application-specific) registry key&lt;/a&gt;, and then call into the add-in DLL using only the &lt;a href="http://msdn.microsoft.com/en-us/library/extensibility.idtextensibility2.aspx"&gt;IDTExtensibility2&lt;/a&gt; interface. &lt;/li&gt; &lt;ul&gt; &lt;li&gt;&lt;em&gt;Side-bar #1&lt;/em&gt;: If you're a VSTO developer who is thinking "IDTExtensibility-what???", VSTO abstracts the &lt;a href="http://msdn.microsoft.com/en-us/library/extensibility.idtextensibility2.aspx"&gt;IDTExtensibility2&lt;/a&gt; interface implementation away from your add-in code. The VSTO runtime implements this interface for you, and forwards the most interesting calls into this interface on to the &lt;em&gt;ThisAddIn_Startup&lt;/em&gt; and &lt;em&gt;ThisAddIn_Shutdown&lt;/em&gt; event handlers in your add-in code.&lt;/li&gt;&lt;/ul&gt; &lt;ul&gt; &lt;li&gt;&lt;em&gt;Side-bar #2&lt;/em&gt;: If you clicked on the &lt;a href="http://msdn.microsoft.com/en-us/library/extensibility.idtextensibility2.aspx"&gt;IDTExtensibility2&lt;/a&gt; link and are wondering why you wound up in the Visual Studio extensibility documentation, this is because this interface (and the Extensibility.dll assembly that defines it) is also used to build Visual Studio add-ins.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;p&gt;The implication of these differences is that if you implement the smart tag COM interfaces in a VSTO add-in assembly, your assembly will be loaded twice: once as an add-in, and again as a smart tag DLL. Depending on the size of your add-in, this could result in a lot of redundant code being loaded into memory. Furthermore, because every VSTO add-in is loaded into a separate application domain, the two instances of your assembly will be in separate application domains, and cannot easily share code or data. Because of these issues, there is not much of a benefit to implement a COM smart tag in a VSTO add-in.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font size="4"&gt;Calling Into A VSTO Add-in From a COM Smart Tag—Is It Possible?&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;If you're following me this far, your next question might be "OK, so if I implement a COM smart tag DLL and a VSTO add-in as part of my overall Office solution, how can I call into my add-in from my smart tag?" Because there are many Office customization features that can be used only in an add-in, you can probably think of many scenarios where this might be useful. For example, you might implement a &lt;a href="http://msdn.microsoft.com/en-us/library/aa942864.aspx"&gt;custom task pane&lt;/a&gt; in an add-in for Excel, and you want to display unique information on this task pane when the user clicks a smart tag action in any open workbook. When the user clicks your action, how can your smart tag tell your add-in to display data in the custom task pane?&lt;/p&gt; &lt;p&gt;There are a number of ways you can do this. Any technology that enables you to communicate between application domains, such as &lt;a href="http://msdn.microsoft.com/en-us/library/72x4h507.aspx"&gt;.NET remoting&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/library/ms735119.aspx"&gt;Windows Communication Foundation&lt;/a&gt;, should work, with varying degrees of complexity. However, the easiest way to do this is to &lt;a href="http://msdn.microsoft.com/en-us/library/bb608621.aspx"&gt;expose an object in your add-in to other Office solutions&lt;/a&gt;, and then to call into this object from your smart tag. My next post will show how to do this. &lt;/p&gt; &lt;p&gt;--------------------------------------------------&lt;/p&gt; &lt;p&gt;McLean Schofield, programming writer&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8451621" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vsto/archive/tags/VSTO/default.aspx">VSTO</category><category domain="http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx">McLean Schofield</category><category domain="http://blogs.msdn.com/vsto/archive/tags/smart+tags/default.aspx">smart tags</category></item><item><title>Visual Studio Command Bar for Arranging Controls on Documents and Worksheets (McLean Schofield)</title><link>http://blogs.msdn.com/vsto/archive/2008/04/10/visual-studio-command-bar-for-arranging-controls-on-documents-and-worksheets.aspx</link><pubDate>Fri, 11 Apr 2008 00:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8376521</guid><dc:creator>VSTO Team</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/vsto/comments/8376521.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vsto/commentrss.aspx?PostID=8376521</wfw:commentRss><description>&lt;P&gt;One of the lesser-known features of Visual Studio Tools for Office is the &lt;STRONG&gt;Microsoft Office Word&lt;/STRONG&gt; and &lt;STRONG&gt;Microsoft Office Excel&lt;/STRONG&gt; command bar. When you are developing a document-level project for Word or Excel (for example, a Word Document or Excel Workbook project) and you have the document or one of your worksheets open in the designer, this command bar appears in Visual Studio, just above the designer. In Excel, this command bar looks like the following by default. 
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_10.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_10.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=168 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_1.png" width=497 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_1.png"&gt;&lt;/A&gt;&amp;nbsp; 
&lt;P&gt;The first several buttons in this command bar are for changing the keyboard scheme and mapping XML to the document or worksheet. This post is about the purpose of the rest of the buttons. 
&lt;P&gt;If you are designing a custom UI for your document or worksheet that includes Windows Forms controls that you add by using the designer, you can use these buttons to arrange the controls with a single click. When you select multiple controls in the designer, these buttons become enabled. 
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image16.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image16.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=37 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image16_thumb.png" width=263 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image16_thumb.png"&gt;&lt;/A&gt;&amp;nbsp; 
&lt;P&gt;From left to right, here are the buttons you can use: 
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Align Lefts&lt;/STRONG&gt;. This button moves all of the controls to the left, so that they are aligned with the left side of the left-most control.&lt;/P&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Align Centers&lt;/STRONG&gt;. This button moves all of the controls left or right so that they are aligned around the vertical axis of the widest control.&lt;/P&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Align Rights&lt;/STRONG&gt;. This button moves all of the controls to the right, so that they are aligned with the right side of the right-most control.&lt;/P&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Align Tops&lt;/STRONG&gt;. This button moves all of the controls up, so that they are aligned with the top side of the upper-most control.&lt;/P&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Align Middles&lt;/STRONG&gt;. This button moves all of the controls up or down, so that they are aligned around the horizontal axis of the tallest control.&lt;/P&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Align Bottoms&lt;/STRONG&gt;. This button moves all of the controls down, so that they are aligned with the bottom side of the bottom-most control.&lt;/P&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Make Horizontal Spacing Equal&lt;/STRONG&gt;. The left-most and right-most control remain in place; the controls in between move horizontally so that there is equal horizontal space between each control.&lt;/P&gt;
&lt;LI&gt;&lt;STRONG&gt;Make Vertical Spacing Equal&lt;/STRONG&gt;. The top-most and bottom-most control remain in place; the controls in between move vertically so that there is equal vertical space between each control.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;A special note about Word.&lt;/STRONG&gt; In Word projects, the alignment buttons are enabled only if the selected controls are &lt;EM&gt;not&lt;/EM&gt; in line with text. By default, controls that you add to a Word document at design time are in line with text. To change the layout style of the control, right-click the control and then click &lt;STRONG&gt;Format Control&lt;/STRONG&gt;. Then, on the &lt;STRONG&gt;Layout&lt;/STRONG&gt; tab, select a wrapping style other than &lt;STRONG&gt;In line with text&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image55.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image55.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=202 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image55_thumb.png" width=461 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image55_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Examples.&lt;/STRONG&gt; Enough words! Here are some examples that show these alignment options in action. These examples are pretty contrived, but they should give you an idea of the effects of each option.&lt;/P&gt;
&lt;P&gt;Given the following buttons on a worksheet:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image19.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image19.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=232 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image19_thumb.png" width=384 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image19_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Align Lefts&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_16.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_16.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=244 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_7.png" width=240 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_7.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Align Centers&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_18.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_18.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=244 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_8.png" width=238 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_8.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;And &lt;STRONG&gt;Align Rights&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_20.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_20.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=244 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_9.png" width=240 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image_thumb_9.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Given the following buttons on a worksheet:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image40.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image40.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=221 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image40_thumb.png" width=398 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image40_thumb.png"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Align Tops&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image43.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image43.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=116 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image43_thumb.png" width=400 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image43_thumb.png"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Align Middles&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image37.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image37.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=136 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image37_thumb.png" width=406 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image37_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;And &lt;STRONG&gt;Align Bottoms&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image46.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image46.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=134 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image46_thumb.png" width=400 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image46_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Given the following buttons on a worksheet:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image49.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image49.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=56 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image49_thumb.png" width=566 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image49_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Make Horizontal Spacing Equal&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image52.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image52.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=54 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image52_thumb.png" width=576 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image52_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Finally, given the following buttons on a worksheet:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image64.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image64.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=306 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image64_thumb.png" width=173 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image64_thumb.png"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Make Vertical Spacing Equal&lt;/STRONG&gt; rearranges the controls as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image67.png" mce_href="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image67.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=297 alt=image src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image67_thumb.png" width=186 border=0 mce_src="http://blogs.msdn.com/blogfiles/vsto/WindowsLiveWriter/HiddenVSTOFeature_9861/image67_thumb.png"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope these options come in handy then next time you are adding controls to a document or worksheet in VSTO.&lt;/P&gt;
&lt;P&gt;-------------------------------------------------&lt;/P&gt;
&lt;P&gt;McLean Schofield, Programming Writer&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8376521" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vsto/archive/tags/Command+bars/default.aspx">Command bars</category><category domain="http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx">McLean Schofield</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Excel+2003/default.aspx">Excel 2003</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Word+2007/default.aspx">Word 2007</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Word+2003/default.aspx">Word 2003</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Excel+2007/default.aspx">Excel 2007</category></item><item><title>Word Object Model: Getting Information from Word Dialogs (McLean Schofield)</title><link>http://blogs.msdn.com/vsto/archive/2008/02/19/word-object-model-getting-information-from-word-dialogs.aspx</link><pubDate>Wed, 20 Feb 2008 03:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7805848</guid><dc:creator>VSTO Team</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/vsto/comments/7805848.aspx</comments><wfw:commentRss>http://blogs.msdn.com/vsto/commentrss.aspx?PostID=7805848</wfw:commentRss><description>&lt;P&gt;Although VSTO provides many features that help simplify Office development (especially UI development), nearly every VSTO solution needs to dip into the underlying Office object model to get some work done. Because information about using the Office object models can be spread out in many different places, I thought it might help some readers who are just getting started with Office development using VSTO to talk about a Word object model question that came across my desk recently. 
&lt;P&gt;A developer on an internal alias inside Microsoft asked about the best way to programmatically show the &lt;STRONG&gt;Insert Picture&lt;/STRONG&gt; dialog box in a Word add-in, and how to perform some logic based upon the full name of the picture that the user selects. The developer had no trouble displaying this dialog box, but couldn't figure out how to get the file name of the chosen picture. 
&lt;P&gt;As the developer noticed, displaying the Insert Picture dialog box (or any built-in Word dialog box, for that matter), is pretty straightforward. The trickiest part is determining which WdWordDialog enum value to pass as an index to the ThisAddIn.Application.Dialogs property in the VSTO project. By referring to the VBA documentation for the WdWordDialog enum at &lt;U&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/bb214033.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb214033.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb214033.aspx&lt;/A&gt;&lt;/U&gt; and scanning through the list of values for something that matches the name of the Insert Picture dialog box, you will eventually find the value wdDialogInsertPicture. 
&lt;P&gt;So, the code to display this dialog box looks like: 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 'VB&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim dialogBox As Word.Dialog = Globals.ThisAddIn.Application.Dialogs(Word.WdWordDialog.wdDialogInsertPicture)&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; dialogBox.Show()&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // C#&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Word.Dialog dialogBox = Globals.ThisAddIn.Application.Dialogs[Word.WdWordDialog.wdDialogInsertPicture];&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; dialogBox.Show();&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&lt;/FONT&gt;&lt;/P&gt;Now comes the hard part: how to use the Dialog object to get or set data contained in the corresponding dialog box. For example, when the end user uses the Insert Picture dialog box to select a picture file, how can I programmatically determine which file they selected? 
&lt;P&gt;The Dialog object (reference topic at &lt;A href="http://msdn2.microsoft.com/en-us/library/bb211882.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb211882.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb211882.aspx&lt;/A&gt;) doesn't provide much help. A quick look through its members doesn't show anything obviously useful or pertinent, like a "FileName" property anything like that. However, the reference topic for the WdWordDialog enum (&lt;U&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/bb214033.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb214033.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb214033.aspx&lt;/A&gt;&lt;/U&gt;) says something interesting (emphasis mine): 
&lt;P&gt;"Indicates the Microsoft Office Word dialog boxes with which you can work &lt;EM&gt;and specifies arguments, if applicable, that you can use to get or set values in a dialog box&lt;/EM&gt;." 
&lt;P&gt;This helps. So, for each WdWordDialog enum value, the table in this topic specifies the properties you can use to get or set information in the dialog box. For wdDialogInsertPicture, there are Name, LinkToFile, New, and FloatOverText properties. Of these, Name looks the most promising. So, how do we use the Name property if the Dialog class doesn't have this property? 
&lt;P&gt;The answer, as is often the case when using the Office object models, is late binding. The Name property is accessible only as a late-bound property, so the way that you use it in a VSTO project depends on the type of project you are developing: 
&lt;UL&gt;
&lt;LI&gt;You are using Visual Basic with Option Strict set to Off. 
&lt;LI&gt;You are using C# or Visual Basic with Option Strict set to On.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;If you're using VB with Option Strict set to Off, then you can use the following relatively simple code, which relies on late binding to access the Name property on the Dialog object at run time. After the Insert Picture dialog box is displayed, if the user selects a picture file and clicks Insert, then this code gets the full path of the selected file and displays the path in a message box: 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 'VB&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim DialogResultOK As Integer = -1&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; With Globals.ThisAddIn.Application.Dialogs(Word.WdWordDialog.wdDialogInsertPicture)&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Courier size=2&gt;If .Show() = DialogResultOK Then&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Windows.Forms.MessageBox.Show("The name of the inserted picture is: " &amp;amp; .Name)&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Courier size=2&gt;End If&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Courier size=2&gt;End With&lt;/FONT&gt; 
&lt;P&gt;If you're using C# or Visual Basic with Option Strict set to On, you'll have use reflection: 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // C#&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Word.Dialog dialogBox = Globals.ThisAddIn.Application.Dialogs[Word.WdWordDialog.wdDialogInsertPicture];&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Type dialogType = typeof(Word.Dialog);&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int DialogResultOK = -1;&lt;/FONT&gt;&amp;nbsp; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (dialogBox.Show(ref missing) == DialogResultOK)&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string pictureName = (string)dialogType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty | &lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, dialogBox, null);&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Windows.Forms.MessageBox.Show("The name of the inserted picture is: " + pictureName);&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=Courier size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt; 
&lt;P&gt;This is one of those areas where the late-bound features of Visual Basic help make it a natural fit for Office programming. Granted, anything you can do in Visual Basic in terms of Office development is possible in C#, but it just isn't always as straightforward or elegant. 
&lt;P&gt;Some of you reading this might be wondering if they have to go digging around in the VBA reference documentation every time they need to figure out how to do something with the Office object models in VSTO. Not always - the VSTO documentation provides a set of "how to" topics with code examples for some of the most common programming tasks using the Excel and Word object models (see the topics under &lt;A title=http://msdn2.microsoft.com/en-us/library/kw65a0we.aspx href="http://msdn2.microsoft.com/en-us/library/kw65a0we.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/kw65a0we.aspx"&gt;http://msdn2.microsoft.com/en-us/library/kw65a0we.aspx&lt;/A&gt; for Word and &lt;A title=http://msdn2.microsoft.com/en-us/library/bb386293.aspx href="http://msdn2.microsoft.com/en-us/library/bb386293.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb386293.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb386293.aspx&lt;/A&gt; for Excel). In fact, most of the information in this post is covered in the topic "How to: Use Built-In Dialog Boxes in Word" at &lt;A title=http://msdn2.microsoft.com/en-us/library/ahzbkf8e.aspx href="http://msdn2.microsoft.com/en-us/library/ahzbkf8e.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ahzbkf8e.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ahzbkf8e.aspx&lt;/A&gt;.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7805848" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/vsto/archive/tags/Word+Object+Model/default.aspx">Word Object Model</category><category domain="http://blogs.msdn.com/vsto/archive/tags/Dialog+boxes/default.aspx">Dialog boxes</category><category domain="http://blogs.msdn.com/vsto/archive/tags/McLean+Schofield/default.aspx">McLean Schofield</category></item></channel></rss>