1838 lines
103 KiB
HTML
1838 lines
103 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml" xml:lang="en" lang="en">
|
|
<head>
|
|
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
|
<meta name="keywords" content="list view, listview, list view control, list view component, .net list view, list view replacement, list view alternative, improved list view, enhanced list view" />
|
|
<meta name="description" content="Better ListView by Component Owl is a .NET WinForms control designed to replace the standard list view control included with C#/VB.net." />
|
|
<meta name="author" content="Dextronet" />
|
|
<meta http-equiv="Title" content="Visual Studio Toolbox Control Integration - visual studio" />
|
|
<meta name="copyright" content="(c) 2010-2018 Dextronet" />
|
|
<meta name="distribution" content="Global" />
|
|
<meta name="rating" content="General" />
|
|
<meta name="robots" content="All" />
|
|
<meta http-equiv="Content-Language" content="en" />
|
|
<meta name="verify-v1" content="NK0H1gWia1vxGZ2Yhr59gsS0/P2/USBI1DVA18VkzjM=" />
|
|
<meta name="google-site-verification" content="O7Dwtzu5x_Mob9u98uxqpZ-_wCLGpEkx2IL0UYVQ4ac" />
|
|
<title>Visual Studio Toolbox Control Integration - visual studio</title>
|
|
<link rel="alternate" type="application/rss+xml" title="Component Owl Feed: Latest releases, news and tips & tricks from our blog" href="../feeds.rss" />
|
|
<link rel="alternate" type="application/rss+xml" title="Component Owl's Comics: Latest comic strips for developers by Libor Tinka" href="../comics.rss" />
|
|
<link href="../stylesheets/base_packaged.css%3F1455269822.css" media="screen" rel="stylesheet" type="text/css" />
|
|
|
|
</head>
|
|
<body>
|
|
|
|
<div class="d-page">
|
|
|
|
<script type="text/javascript">
|
|
//<![CDATA[
|
|
var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_email":"a valid email","thanks_for_why_uninstall":"Thank you very much for your feedback!","thank_you":"Thank you!","current_email":"valid current email","thanks_for_subscription":"<div class=\"sent-saved-notice\">Thank You for your subscription!<br /><button type=\"button\" onclick=\"close_fancybox();\">Close</button>","message":"message","required":"required","download_in_progress":"Your download should be in progress...","your_full_name":"your full name","order_thanks_for_message":"<div class=\"sent-saved-notice\">Thank you very much for your message!<br /><button type=\"button\" onclick=\"close_fancybox();\">Close</button>","thanks_for_message":"Thank you very much for your message!<br /><a href="http://www.componentowl.com/articles/\"#\"" onclick=\"send_another(); return false;\">Send Another Message</a>"}
|
|
//]]>
|
|
</script>
|
|
|
|
<div class="d-header d-placing">
|
|
|
|
<ul class="d-menu">
|
|
<li class=""><a href="../index.html" class="menu-item">Home</a></li>
|
|
<li class=" with-dropdown">
|
|
<a href="../blog/page/6/index.html" class="menu-item">Products</a>
|
|
<div class="dropdown dropdown-submenu" style="display: none; width: 370px"><div class="outer"><div class="shadowbox"><div class="border"><div class="inner">
|
|
|
|
<div class="dropdown-category">WinForms Components</div>
|
|
|
|
|
|
<a href="../blog/page/6/index.html" class="featured-item"><img alt="icon" src="http://assets.componentowl.com/icons/better-listview-32-1355160256.png?1355135056" /> Better ListView<br /><span class="subline">Ultimate ListView control for .NET</span></a>
|
|
|
|
|
|
<a href="../better-thumbnail-browser.html" class="featured-item"><img alt="icon" src="http://assets.componentowl.com/icons/better-thumbnail-browser-32-1355160281.png?1355135081" /> Better Thumbnail Browser<br /><span class="subline">Thumbnail loading and browsing control for .NET</span></a>
|
|
|
|
|
|
<a href="../better-splitbutton.html"><img alt="icon" src="http://assets.componentowl.com/icons/better-splitbutton-32-1355160307.png?1355135107" /> Better SplitButton<br /><span class="subline">Free customizable dropdown button control</span></a>
|
|
|
|
|
|
<a href="../better-listview-express.html"><img alt="icon" src="http://assets.componentowl.com/icons/better-listview-express-32-1355160327.png?1355135127" /> Better ListView Express<br /><span class="subline">Free edition with less features</span></a>
|
|
|
|
|
|
</div></div></div></div></div>
|
|
</li>
|
|
<li class="">
|
|
<a href="../pricing-licensing/better-listview.html" class="menu-item">Purchase</a>
|
|
<div class="dropdown dropdown-submenu" style="display: none; width: 330px"><div class="outer"><div class="shadowbox"><div class="border"><div class="inner">
|
|
|
|
|
|
|
|
<a href="../pricing-licensing/better-listview.html" class="featured-item">Better ListView</a>
|
|
|
|
|
|
|
|
|
|
<a href="../pricing-licensing/better-thumbnail-browser.html" class="featured-item">Better Thumbnail Browser</a>
|
|
|
|
|
|
|
|
|
|
<a href="../pricing-licensing/better-splitbutton.html">Better SplitButton</a>
|
|
|
|
|
|
|
|
|
|
</div></div></div></div></div>
|
|
</li>
|
|
<li class=""><a href="../support.html" class="menu-item">Support</a></li>
|
|
<li class="active"><a href="../articles.html" class="menu-item">Articles</a></li>
|
|
<li class=""><a href="../blog.html" class="menu-item">Blog</a></li>
|
|
<li class=""><a href="../comics/43.html" class="menu-item">Comics</a></li>
|
|
<li class=""><a href="../about-us.html" class="menu-item">About Us</a></li>
|
|
</ul>
|
|
<div class="d-logo">
|
|
<a href="../index.html" class="logoimg"><img alt="Component Owl" src="../images/componentowl.gif%3F1455269978" /></a>
|
|
<g:plusone size="medium" count="false" href="http://www.componentowl.com"></g:plusone>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="d-placing">
|
|
<div class="d-content-wrap">
|
|
<div class="subpage article-content">
|
|
|
|
<div class="left">
|
|
|
|
<div class="section-heading">Articles for .NET developers</div>
|
|
|
|
<h1 class="title">Visual Studio Toolbox Control Integration</h1>
|
|
|
|
<div class="content">
|
|
<script type="text/javascript">
|
|
/* <![CDATA[ */
|
|
(function() {
|
|
var s = document.createElement('script');
|
|
var t = document.getElementsByTagName('script')[0];
|
|
|
|
s.type = 'text/javascript';
|
|
s.async = true;
|
|
s.src = '//api.flattr.com/js/0.6/load.js?mode=auto&uid=libca&language=en_US';
|
|
|
|
t.parentNode.insertBefore(s, t);
|
|
})();
|
|
/* ]]> */
|
|
</script>
|
|
|
|
<div style="text-align: center; padding-top: 1em">
|
|
<a class="FlattrButton" href="visual-studio-toolbox-control-integration.html" title="article-toolbox-integration" lang="en-us" rel="flattr;uid:libca;title:article-toolbox-integration;language:en_US">
|
|
Visual Studio Toolbox Control Integration
|
|
</a>
|
|
</div>
|
|
|
|
<h1>The Most Complete Guide to Visual Studio Toolbox Control Integration</h1>
|
|
<p><a href="mailto:libca@libca.cz?subject=article-vs-toolbox-integration">Libor
|
|
Tinka</a>, Lead Developer, ComponentOwl.com</p>
|
|
<p><a href="../comics/10.html">
|
|
<img height="212" src="../images/articles/vs-toolbox-integration/comics.png" width="627" /></a></p>
|
|
<h2>Contents</h2>
|
|
<p><a href="visual-studio-toolbox-control-integration.html#introduction">1. Introduction</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#prerequisites">2. Prerequisites</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#sample-control">3. Creating a Sample Control</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#integration-manual">4. Manual Toolbox Integration</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#integration-tci">5. Toolbox Integration using TCI</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#integration-dte">6. Toolbox Integration using DTE</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#integration-vsi">7. Toolbox Integration using VSI Packages</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#integration-vspackage">8. Toolbox Integration using VSPackages</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#integration-vsix">9. Toolbox Integration using VSIX Packages</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#net-versions">10. Supporting Multiple Version of .NET Framework</a><br />
|
|
<a href="visual-studio-toolbox-control-integration.html#source">11. Sample Source Code</a></p>
|
|
<h2><a name="introduction">1. Introduction</a></h2>
|
|
<p>This tutorial is intended for developers who would like to distribute their
|
|
WPF or WinForms controls and automatically put them into Visual Studio Toolbox
|
|
during installation.</p>
|
|
<p>I struggled with Toolbox integration earlier because there are several possible
|
|
approaches (harder to decide between them). Each approach have its own pros and cons and
|
|
no overall comparison is provided. I wrote this tutorial to shed some light on the topic
|
|
and spare you hours, maybe days of research and experimenting with aspects of
|
|
Visual Studio (Toolbox) extensibility.</p>
|
|
<p>We will first take a look on Toolbox control integration in general to get a
|
|
big picture. Each approach will be then discussed in detail and the following
|
|
question will be answered:</p>
|
|
<ul class="common">
|
|
<li>How to install control in Visual Studio Toolbox?</li>
|
|
<li>How to update the control?</li>
|
|
<li>How to uninstall/remove the control?</li>
|
|
<li>How to support multiple Visual Studio versions?</li>
|
|
</ul><br />
|
|
<p>There are several options on how to integrate your controls with Visual
|
|
Studio Toolbox:</p>
|
|
<ul class="common">
|
|
<li>Manual installation</li>
|
|
<li>Toolbox Control Installer (TCI)</li>
|
|
<li>Visual Studio Automation Object Model (DTE)</li>
|
|
<li>VSPackage</li>
|
|
<li>VSI package</li>
|
|
<li>VSIX package</li>
|
|
</ul>
|
|
<h3>Manual installation</h3>
|
|
<p>The simplest way of adding control into Visual Studio Toolbox is from within
|
|
the IDE.</p>
|
|
<p>This approach have one crucial drawback, which is that you leave Toolbox
|
|
integration to the user. Many developers are not that experienced with Visual
|
|
Studio and when your component is shipped, even if you provide appropriate
|
|
step-by-step guide, they may find it too complicated and rather try
|
|
another component which "just works". I thought that every developer using
|
|
Visual Studio is experienced enough to know how to add new items in VS Toolbox,
|
|
but I received few e-mails from users who uninstalled the product just because
|
|
the component have not appeared in the Toolbox and they thought it is broken
|
|
(without reading our documentation, of course). On the other hand, there is
|
|
a group of users who are not experienced developers, but are in charge of trying
|
|
some products in a given company (e.g. project managers). These people can
|
|
install the component, play with it and they would really appreciate if it just
|
|
works. This increases chance they will actually purchase your product.</p>
|
|
<p><strong>Advantages:</strong> zero effort<br />
|
|
<strong>Disadvantages:</strong> require experienced users, slows user
|
|
producitivity, updating controls is not intuitive</p>
|
|
<h3>Toolbox Control Installer (TCI)</h3>
|
|
<p>Visual Studio 2005 SDK contained a VSPackage called Toolbox Control
|
|
Installer. This package comes pre-installed with Visual Studio 2008 and newer.
|
|
Its job is to simplify the specific task of extending Visual Studio Toolbox.
|
|
This approach requires you to install your assembly in GAC (Global Assembly
|
|
Cache) and create a key in Windows Registry.</p>
|
|
<p><strong>Advantages:</strong> simple and fast component installation, updating
|
|
and removing<br />
|
|
<strong>Disadvantages:</strong> requires installation in GAC (not always
|
|
wanted), VS 2005 supported with SDK only</p>
|
|
<h3>Visual Studio Automation Object Model (DTE)</h3>
|
|
<p>If you are not afraid of COM, you can try DTE (Development Tools Environment) approach.
|
|
There is already a project on CodePlex called
|
|
<a href="http://vstudiotoolbox.codeplex.com/">Visual Studio Toolbox Manager</a>,
|
|
which solves the toolbox integration problem using a simple command-line
|
|
application. The project is outdated since it does not support Visual Studio
|
|
2010 and newer. I made a project called <strong>DteToolboxInstaller</strong>, which
|
|
is also a command-line application and <em>does</em> support Visual Studio 2013, 2012, 2010,
|
|
2008 and 2005. You can use the project as you like. The main disadvantage of DTE
|
|
approach is the speed. The installer have to run devenv.exe using the automation interface, create a
|
|
fake VS Solution, open Toolbox, add the stuff and then close the Solution. The
|
|
whole process take no less than 10 seconds. If you want to integrate with two or
|
|
three versions of Visual Studio, it can take well over a minute.</p>
|
|
<p><strong>Advantages:</strong> does not require updating registry or GAC, full
|
|
control over Toolbox<br />
|
|
<strong>Disadvantages:</strong> very slow, separate installation required for
|
|
every version of Visual Studio</p>
|
|
<h3>VSPackage</h3>
|
|
<p>A VSPackage seems to be a natural option. VSPackages allow any type
|
|
of Visual Studio extension and you can manipulate Toolbox as well. There was a trouble
|
|
with VSPackages in providing a Package Load Key (PLK) which can be
|
|
generated only manually using web form. The requirement for PLK vanished with
|
|
Visual Studio 2010 (hooray!). The nice thing about VSPackage approcach is that it does not slow
|
|
down the installation process. The package is loaded and the controls are installed
|
|
on-demand (when the Toolbox is opened for the first time after installation).
|
|
After trying all the approaches, using VSPackage seems to be fastest and most
|
|
universal one.</p>
|
|
<p><strong>Advantages:</strong> quick installation, appearance in About box and
|
|
other extensibility features<br />
|
|
<strong>Disadvantages:</strong> cmplicated setup, each component requires its
|
|
own package if shipped separately</p>
|
|
<h3>VSI Package</h3>
|
|
<p>VSI packages are quite old but you can use them for integration with Visual
|
|
Studio 2005 and newer. It have very simple structure and you can create one even
|
|
without Visual Studio. The only trouble with VSI compared to other
|
|
approaches is invoking a wizard form which cannot be suppressed. The
|
|
installation just cannot run in "quiet" mode. Another trouble with VSI is that a
|
|
digital signature is required in order to get rid of a warning dialog. Your control will be always installed under "My Controls" tab in the
|
|
Toolbox, which is not always desirable.</p>
|
|
<p><strong>Advantages:</strong> simple creation, installer provided by Visual
|
|
Studio, automated creation and signing requires several specific steps<br />
|
|
<strong>Disadvantages:</strong> no quiet mode (extra steps when custom installer
|
|
is used), manual uninstallation</p>
|
|
<h3>VSIX Package</h3>
|
|
<p>VSIX packages came with Visual Studio 2010 so you can integrate with 2010 or
|
|
newer. the .VSI and .VSIX file extensions are associated with Visual Studio so
|
|
you can simply double-click it or run it via shell. You can also run
|
|
VsixInstaller.exe utility that performs the installation. Good news: No more
|
|
nag screens when VSIX is not signed - the installer only contains a dialog with
|
|
simple text: <em>"This extension does not contain a digital signature."</em>
|
|
Even better news: The VsixInstaller supports quiet mode!</p>
|
|
<p>Please note that VSI and VSIX package installers contain features like
|
|
displaying EULA, choosing which components to install or localization. When
|
|
deploying your controls for use in Visual Studio, you won't need an installer on
|
|
top of the package.</p>
|
|
<p><strong>Advantages:</strong> installer provided by Visual Studio, quiet mode,
|
|
fast installation<br />
|
|
<strong>Disadvantages:</strong> package project required, automated creation is
|
|
complicated, no support for VS 2005 and 2008</p>
|
|
<h3>Comparison of Approaches</h3>
|
|
<p>Here is a table summarizing features of the discussed approaches. As you can
|
|
see, the VSPackage approach gives you the most freedom, but is also hardest
|
|
to implement. We will discuss every approach so
|
|
that you will be able to impement the one that suits you best.</p>
|
|
<table style="width: 100%">
|
|
<tr>
|
|
<td> </td>
|
|
<td><b>2005</b></td>
|
|
<td><b>2008</b></td>
|
|
<td><b>2010</b></td>
|
|
<td><b>2012</b></td>
|
|
<td><b>2013</b></td>
|
|
<td><b>Speed</b></td>
|
|
<td><b>Install Automation</b></td>
|
|
<td><b>Uninstall automation</b> </td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Manual installation</strong></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td>depends on user</td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>TCI</b></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-warning.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td>fast</td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-na.png" width="16" /> </td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>EnvDTE</b></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td>slow</td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /> </td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>VSI</b></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td>moderate</td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /> </td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>VSIX</b></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td>moderate (faster than VSI)</td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-no.png" width="16" /> </td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>VSPackage</b></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td>fast</td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /></td>
|
|
<td><img height="16" src="../images/articles/vs-toolbox-integration/comparison-yes.png" width="16" /> </td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2><a name="prerequisites">2. Prerequisites</a></h2>
|
|
<p>We will focus on integration with Visual Studio 2010, 2012 and 2013. Hence you will need:</p>
|
|
<ul class="common">
|
|
<li><strong>Visual Studio 2010 (or 2012, 2013)</strong></li>
|
|
<li><strong>Visual Studio 2010 SDK (or 2012 SDK, 2013 SDK)</strong></li>
|
|
<li><strong>Microsoft Windows SDK</strong></li>
|
|
</ul>
|
|
<p>The VS SDK contains regpkg.exe tool and project templates discussed in VSIX
|
|
and VSPackage approaches.</p>
|
|
<p>The Windows SDK contains gacutil.exe, guidgen.exe, signtool.exe and other
|
|
useful tools.</p>
|
|
<p>There are two kinds of versioning used for Visual Studio. One is based on the
|
|
release name (e.g. Visual Studio 2008) and the other is a classic version number
|
|
(e.g. 8.0). Both will be used, so it should be noted which version numbers
|
|
correspond to which versions of Visual Studio:</p>
|
|
<table style="width: 100%">
|
|
<tr>
|
|
<td><strong>Release name</strong></td>
|
|
<td><strong>Version number</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Visual Studio 2005</td>
|
|
<td>8.0</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Visual Studio 2008</td>
|
|
<td>9.0</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Visual Studio 2010</td>
|
|
<td>10.0</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Visual Studio 2012</td>
|
|
<td>11.0</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Visual Studio 2013</td>
|
|
<td>12.0</td>
|
|
</tr>
|
|
</table>
|
|
<h2><a name="sample-control">3. Creating a Sample Control</a></h2>
|
|
<p>We will start by creating simple WinForms control for integration in VS
|
|
Toolbox.</p>
|
|
<p>You can start with File - New - Project... (Control+Shift+N) and select
|
|
<strong>Windows Forms Controls Library</strong> template.</p>
|
|
<p>Of course, you can also create empty Class Library project, add references to
|
|
System.Drawing and System.Windows.Forms and create a new control. In fact, any
|
|
DLL containing public classes derived from <strong>Control</strong> will
|
|
suffice.</p>
|
|
<p>We want to support .NET Runtime version 4.0 and 4.5, so the control should be
|
|
built against .NET 4.0 to ensure compatibility (the lower framework version you
|
|
use, the wider range of compatible frameworks since they are backward
|
|
compatible). It should be noted that .NET 4.5 is an in-place update of .NET 4.0
|
|
and hence the 4.5 assemblies will work on machines with 4.0 runtime installed
|
|
<em>unless</em> you use some feature specific to 4.5.</p>
|
|
<p>If you have multiple controls in your assembly and don't want to use some of
|
|
them in Toolbox, decorate them with <strong>ToolboxItem</strong> attribute with
|
|
<strong>defaultType</strong> parameter set to <strong>false</strong>:</p>
|
|
<pre>
|
|
<strong>[ToolboxItem(false)]</strong>
|
|
public class InvisibleControl : UserControl
|
|
{
|
|
...
|
|
}
|
|
</pre>
|
|
<p>I have created a very simple control called <strong>SampleControl</strong>:</p>
|
|
<p><img height="173" src="../images/articles/vs-toolbox-integration/sample-control.png" width="173" /></p>
|
|
<p>Finally, I set version of the assembly 3.3.0.0 (I chose just something else
|
|
than 1.0.0.0 to see where the specific version number appears).</p>
|
|
<h3>Custom Transparent Icon for the Toolbox</h3>
|
|
<p>Icons for Toolbox are 16 by 16 pixel images. Various image formats are supported
|
|
(BMP, JPEG, PNG and ICO). However, you need to
|
|
create 256-color BMP image to ensure transparency. The transparent color is determined by bottom left
|
|
pixel of the icon. Transparency works for magenta (#ff00ff):</p>
|
|
<p><img height="128" src="../images/articles/vs-toolbox-integration/toolbox-icon.png" width="128" /></p>
|
|
<p>The icon file should have same name as the control class (i.e. <strong>
|
|
SampleControl.BMP</strong>).</p>
|
|
<p>Finally, use <strong>ToolboxBitmapAttribute</strong> to link icon with the control class:</p>
|
|
<pre>
|
|
<strong>[ToolboxBitmap(typeof(SampleControl), "Resources.SampleControl.bmp")]</strong>
|
|
public partial class SampleControl : UserControl
|
|
{
|
|
...
|
|
}
|
|
</pre>
|
|
<p>Note that icon location matters, at least in C#. Since I have added
|
|
the icon under custom folder named <strong>Resources</strong>, I need to reference
|
|
<strong>Resources.SampleControl.bmp</strong> instead of just <strong>SampleControl.bmp</strong>.</p>
|
|
<p>Here is the resulting transparent icon in Toolbox:</p>
|
|
<p><img height="337" src="../images/articles/vs-toolbox-integration/toolbox-2.png" width="254" /></p>
|
|
<h3>Marking the Control as Toolbox Item</h3>
|
|
<p>We can mark control as toolbox item by adding a <strong>ToolboxItemAttribute </strong>
|
|
with<strong> defaultType </strong>parameter set to <strong>true</strong>:</p>
|
|
<pre>
|
|
<strong>[ToolboxItem(true)]</strong>
|
|
public partial class SampleControl : UserControl
|
|
...
|
|
</pre>
|
|
<p>This decoration is optional since the controls within assembly are
|
|
considered toolbox items by default. However, we can mark certain control
|
|
classes with <strong>ToolboxItem(false)</strong> to hide them from Toolbox. This
|
|
comes in handy when we have multiple projects and there are too many controls in
|
|
the Toolbox because loaded from all the other projects.</p>
|
|
<h3>Signing the Assembly</h3>
|
|
<p>The assembly containing controls (<strong>SampleControl.dll</strong> in our
|
|
case) should be strongly named if we want them installed in GAC
|
|
(Global Assembly Cache) later on. This is optional in most cases, but the Toolbox Controls
|
|
Installer approach requires the assembly being installed in GAC, hence the
|
|
strong name is necessary there.</p>
|
|
<p>To give an assembly a strong name, open project properties and find <strong>
|
|
Signing</strong> tab:</p>
|
|
<p><img height="236" src="../images/articles/vs-toolbox-integration/sample-control-sign.png" width="774" /></p>
|
|
<p>Check the "<strong>Sign the assembly</strong>" option and select "<strong><New...></strong>"
|
|
from the combo box. This will create a new .SNK file in your project which will
|
|
be used to sign the assembly. You can also browse for existing key file. If you
|
|
want to distribute multiple assemblies with custom controls, it is a best
|
|
practice to use same strong name key for each assembly (it is possible to have
|
|
one .SNK file located in Solution folder and put just a link to that file in
|
|
each project; when we browse for the key under the Signing tab, the link will be
|
|
used without copying the file).</p>
|
|
<p>The SNK (Strong Name Key) file is basically a private key to digitally sign
|
|
your assembly. There is also a public key which can be used to verify the
|
|
assembly and its shorter variant called "public key token" for assembly
|
|
identification.</p>
|
|
<h2><a name="integration-manual">4. Manual Toolbox Integration</a></h2>
|
|
<h3>Installing</h3>
|
|
<p>To install component into Visual Studio Toolbox manually, open some form or
|
|
control in designer, open the <strong>Toolbox</strong> window (Control+Alt+X), right-click on the
|
|
Toolbox window and select "<strong>Choose Items...</strong>":</p>
|
|
<p><img height="225" src="../images/articles/vs-toolbox-integration/toolbox-choose-items.png" width="328" /></p>
|
|
<p>The "<strong>Choose Toolbox Items</strong>" dialog will show up:</p>
|
|
<p><img height="483" src="../images/articles/vs-toolbox-integration/choose-toolbox-items.png" width="673" /></p>
|
|
<p>You can browse for DLL file with your component by clicking the "<strong>Browse...</strong>"
|
|
button.</p>
|
|
<p>This is the simplest way of putting component in the Toolbox without extra
|
|
actions required.</p>
|
|
<p>This can be unpleasant for end-users since it means many clicks they have
|
|
to perform. I will explain how to integrate a component a little bit more so that it
|
|
will be visible under the ".NET Framework Components" tab in the above dialog box and
|
|
possibly show up in Toolbox automatically without extra effort of the user.</p>
|
|
<h3>Making the Control Visible in "Choose Toolbox Items" Dialog Box</h3>
|
|
<p>As you can see on the above picture, the SampleControl component is already
|
|
displayed in the dialog box under ".NET Framework Components" tab.</p>
|
|
<p>This is because the folder containing our control is registered as "assembly folder" in the
|
|
registry and hence is searched when the above dialog is populated.</p>
|
|
<p>You can register your own assembly this way by creating a key in registry:</p>
|
|
<pre>32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\<strong><your control name></strong>
|
|
64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\<strong><your control name></strong></pre>
|
|
<p>You can also create key for specific version of .NET runtime (this comes in
|
|
handy if you distribute different components for different versions of .NET):</p>
|
|
<pre>32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<strong><your control name></strong>
|
|
64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<strong><your control name></strong></pre>
|
|
<p>In both cases, the default value for the key is a string with full path to
|
|
the folder with your assembly.</p>
|
|
<p>You can specify Toolbox tab in which the component should show up by adding
|
|
subkey named "<strong>Toolbox</strong>" with single string value "<strong>TabName</strong>" this value has Toolbox
|
|
tab name as data. When you add such control in the Toolbox, it will reside under
|
|
new tab with the specified name:</p>
|
|
<p>
|
|
<img height="265" src="../images/articles/vs-toolbox-integration/registry-assemblyfolders-toolbox.png" width="511" /></p>
|
|
<p>The control should also appear in "Choose Toolbox Items" dialog box if it
|
|
is installed in Global Assembly Cache.</p>
|
|
<p>The control pops up in the Toolbox automatically in
|
|
its own tab in Visual Studio 2012/2013.</p>
|
|
<h3>Installing the Control in GAC</h3>
|
|
<p>The benefit of GAC (Global Assembly Cache) is that the user needs not to
|
|
browse for your control. He will just select it form the above dialog box
|
|
without having to know where it is actually installed (the dialog is populated
|
|
by controls from "assembly folders" and from the GAC).</p>
|
|
<p>The GAC have one useful feature and disadvantage at the same time: It allows
|
|
holding multiple versions of the same assembly. When user makes reference to
|
|
your control from GAC and set "Specific Version" to <strong>true</strong> in
|
|
Reference Properties window, it will be tied to that version. When you install an
|
|
"update", a new version will be added to GAC, but the user will stay with the
|
|
older one. Of course, the "Choose Toolbox Items" dialog will show both versions,
|
|
so the user can just replace old reference with the new one.</p>
|
|
<p>You can make the installer removing any older versions from GAC during
|
|
installation and add/keep just the newest one. This will force the user to
|
|
replace the reference since it breaks the build.</p>
|
|
<p>You can work with GAC by using tool called <strong>gacutil.exe</strong> or
|
|
from code. We will discuss both approaches.</p>
|
|
<p>The gacutil.exe is located in Microsoft Windows SDK directory. There are two
|
|
such extecutables:</p>
|
|
<pre>c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe
|
|
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe</pre>
|
|
<p>The former is for .NET Framework up to version 3.5. The latter is for
|
|
.NET 4.0 and higher. This is for compatibility reasons as a separate GAC have
|
|
been introduced with .NET 4.0.</p>
|
|
<p>You can install an assembly to GAC by calling:</p>
|
|
<pre>gacutil.exe /i SampleControl.dll</pre>
|
|
<p>To uninstall it, we refer to our assembly by its assembly name, not file
|
|
name:</p>
|
|
<pre>gacutil.exe /u SampleControl</pre>
|
|
<p>Finally, you can check if the assembly is installed in GAC by listing any
|
|
instances of the provided name:</p>
|
|
<pre>gacutil.exe /l SampleControl</pre>
|
|
<p>It is not wise, however, to use <strong>gacutil.exe</strong> from a custom
|
|
installer as it is located in SDK that user might not have installed.
|
|
Furthermore, the SDK license does not allow bundling <strong>gacutil.exe</strong>
|
|
with your installer.</p>
|
|
<p>Some installers like Inno Setup or MSI allow installing in GAC anyway.</p>
|
|
<p>You can also work with GAC using <strong>
|
|
System.EnterpriseServices.Internal.Publish</strong> class. The class have two
|
|
methods: <strong>GacInstall</strong> and <strong>GacRemove</strong>. Both
|
|
methods take just path to assembly file as a parameter, so for example:</p>
|
|
<pre>(new Publish()).GacInstall(assemblyPath);</pre>
|
|
<p>will install the specified assembly in GAC.</p>
|
|
<h3>Updating</h3>
|
|
<p>Updating the control depends on how it is installed and referenced.</p>
|
|
<p>If you have added component in the Toolbox manually via "Choose Toolbox Items"
|
|
dialog box and "Browse..." button, i.e. as a <em>file reference</em>, the
|
|
default property of such reference is that it simply points to the specified
|
|
file no matter which version it have (unless user sets "Specific Version" to
|
|
<strong>true</strong> in reference properties window; the default is <strong>
|
|
false</strong> in this case). Simply replacing the DLL with the control by a newer
|
|
file will suffice. If the user have specified "Specific Version" to <strong>true</strong>,
|
|
the build will break because the reference is no longer valid. He needs to
|
|
replace the reference by a new one pointing on the same file which now have
|
|
newer version.</p>
|
|
<p>If you have added the component from GAC (these components also appear in the
|
|
"Choose Toolbox Items" dialog box), the "Specific Version" property of the
|
|
reference is <strong>true</strong> by default:</p>
|
|
<p><img height="391" src="../images/articles/vs-toolbox-integration/reference-properites.png" width="372" /></p>
|
|
<p>This means that even if you install a newer version of the component in GAC,
|
|
the project will still reference the older version and both versions will reside
|
|
in GAC.</p>
|
|
<p>If you remove all versions of the component from GAC (e.g. using <strong>
|
|
gacutil.exe</strong>) and then install just the newest one, the build will break
|
|
unless the user changed "Specific Version" property to <strong>false</strong>.</p>
|
|
<h3>Removing</h3>
|
|
<p>Removing the manually installed control consists of just reverting all the
|
|
steps done during the installation.</p>
|
|
<p>In case of file references, deleting the file is sufficient.</p>
|
|
<p>In case of tighter integration (GAC, registry), the registry keys need to be
|
|
deleted and the control can be removed from GAC (e.g. using <strong>gacutil.exe</strong>).</p>
|
|
<h3>Resetting Toolbox and Clearing the Toolbox Cache</h3>
|
|
<p>The Toolbox can fall into state where it does not display some items, some are
|
|
duplicate and some can be disabled. Sometimes the only remedy is to let Visual
|
|
Studio rebuild the
|
|
Toolbox from scratch.</p>
|
|
<p>To do that, right-click on the Toolbox window and select "<strong>Reset
|
|
Toolbox</strong>". Visual Studio will go through all the installed packages and reloads
|
|
components into the Toolbox.</p>
|
|
<p>If this won't help, you can perform <em>hard reset</em> of the Toolbox. Exit
|
|
Visual Studio and delete all .TBD files in the following folder:</p>
|
|
<pre>\Users\<user>\AppData\Local\Microsoft\VisualStudio\10.0\</pre>
|
|
<p>It should be up to four files:</p>
|
|
<p><img height="242" src="../images/articles/vs-toolbox-integration/files-toolbox-cache.png" width="499" /></p>
|
|
<p>Once removed, start Visual Studio again. After showing the Toolbox, all items
|
|
should load instead of loading only the cached versions.</p>
|
|
<h2><a name="integration-tci">5. Toolbox Integration using TCI</a></h2>
|
|
<h3>Installing</h3>
|
|
<p>Toolbox Control Installer is a VS package pre-installed in Visual Studio 2008 and
|
|
newer. It looks in Windows registry for components and loads them in the
|
|
Toolbox.</p>
|
|
<p>Before using TCI, one can check if it is installed in the given version of
|
|
VS. For example, the following registry key should exist if the Visual Studio
|
|
2010 have TCI installed:</p>
|
|
<pre>32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\<strong>{2c298b35-07da-45f1-96a3-be55d91c8d7a}</strong>
|
|
64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\<strong>{2c298b35-07da-45f1-96a3-be55d91c8d7a}</strong></pre>
|
|
<p>The TCI package GUID is always the same so you can make the check for any
|
|
version of Visual Studio with the above key (only change the version number from
|
|
10.0 to corresponding version number, of course).</p>
|
|
<p>The only prerequisites for the assembly is that it should have strong name
|
|
(i.e. to be signed). See section "Creating the Sample Control" for more
|
|
information.</p>
|
|
<p>The installation consists of putting the control in GAC (see previous
|
|
section for more information) and creating registry keys.</p>
|
|
<p>Suppose we have the <strong>SampleControl</strong> installed in GAC:</p>
|
|
<p><img height="186" src="../images/articles/vs-toolbox-integration/tci-gac.png" width="677" /></p>
|
|
<p>We will make reference to this assembly from registry by creating the
|
|
following key:</p>
|
|
<pre>32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
|
|
64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c</pre>
|
|
<p>The default value for the key is the Toolbox tab name name you would like to
|
|
have for the component(s), e.g. "Component Owl".</p>
|
|
<h3>Installing in Visual Studio 2012 and 2013</h3>
|
|
<p>One extra step is required to make this work in Visual Studio 2012/2013, which is
|
|
adding the registry key also in its user config hive, i.e.:</p>
|
|
<pre>HKCU\Software\Microsoft\VisualStudio\11.0_Config\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c</pre>
|
|
<p>for VS 2012. Use <strong>12.0_Config</strong> for VS 2013.</p>
|
|
<h3>Updating</h3>
|
|
<p>Updating the component is very simple. Just modify the above registry keys by
|
|
changing the version number.</p>
|
|
<h3>Removing</h3>
|
|
<p>To remove the component, delete the above registry keys. You should also
|
|
remove the corresponding assembly from GAC.</p>
|
|
<h3>Automating Integration with TCI using TciToolboxInstaller</h3>
|
|
<p>I made a simple command-line application called <strong>TciToolboxInstaller</strong>
|
|
which does all the described steps. The usage is simple:</p>
|
|
<pre>TciToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]</pre>
|
|
<p>For example, if you like to install SampleControl.dll in Visual Studio 2012
|
|
Toolbox, just call:</p>
|
|
<pre>TciToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll</pre>
|
|
<p>You can use quotes for the last two parameters if they contain spaces.</p>
|
|
<p>The <strong>TciToolboxInstaller</strong> project is contained in sample
|
|
source code.</p>
|
|
<h2><a name="integration-dte">6. Toolbox Integration using DTE</a></h2>
|
|
<h3>Installing</h3>
|
|
<p>The
|
|
<a href="http://www.codeproject.com/Articles/477550/Developing-extension-packages-for-Visual-Studio-20">DTE</a> (Development Tools Environment) approach does not require working
|
|
with GAC or registry. It remotely manipulates Visual Studio Toolbox and
|
|
adds/removes items as needed.</p>
|
|
<p>The whole installation is done from (managed) code using COM wrappers. It
|
|
works in the following steps:</p>
|
|
<ul class="common">
|
|
<li>Check if an instance of Visual Studio is not running. If not, continue.</li>
|
|
<li>Retrieve an <strong>EnvDTE.DTE</strong> object corresponding to the
|
|
version of Visual Studio we want to integrate with.</li>
|
|
<li>Create a "dummy" project using the <strong>DTE</strong> object</li>
|
|
<li>Obtain Toolbox window and <strong>ToolBox</strong> object from it.</li>
|
|
<li>Find or create <strong>ToolBoxTab</strong> object.</li>
|
|
<li>Add item in the Toolbox tab (<strong>ToolBoxTab.ToolBoxItems.Add</strong>).</li>
|
|
<li>Wait until current instance of Visual Studio stops running.</li>
|
|
</ul>
|
|
<p>Here are some of the step/strongs in C# code - it is an excerpt from <strong>
|
|
DteToolboxInstaller</strong> project provided in sample source code:</p>
|
|
<pre>
|
|
// obtain a DTE object
|
|
Type typeDTE = Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
|
|
|
|
DTE dte = (DTE)Activator.CreateInstance(typeDTE, true);
|
|
|
|
// create a temporary file
|
|
string tempFile = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
|
|
string tempDirectory = string.Format("{0}{1}", Path.GetTempPath(), tempFile);
|
|
|
|
// create Visual Studio Solution
|
|
Solution4 solution = (dte.Solution as Solution4);
|
|
|
|
string templatePath = solution.GetProjectTemplate(TemplateName, "CSharp");
|
|
|
|
solution.AddFromTemplate(templatePath, tempDirectory, DummyProjectName, false);
|
|
|
|
// get Toolbox window
|
|
Window window = dte.Windows.Item(Constants.vsWindowKindToolbox);
|
|
|
|
// get Toolbox
|
|
ToolBox toolBox = (ToolBox)window.Object;
|
|
|
|
// get Toolbox tab
|
|
ToolBoxTab toolBoxTab = (GetToolBoxTab(toolBox.ToolBoxTabs) ?? toolBox.ToolBoxTabs.Add(this.tabName));
|
|
|
|
// add new item under the Toolbox tab
|
|
toolBoxTab.ToolBoxItems.Add(assemblyName, this.assemblyPath, vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
|
|
|
|
// select the Toolbox tab
|
|
toolBoxTab.Activate();
|
|
|
|
// cleanup
|
|
dte.Solution.Close(false);
|
|
dte.Quit();
|
|
Marshal.ReleaseComObject(dte);
|
|
|
|
// wait till Visual Studio turns off completely
|
|
if (IsVisualStudioRunning())
|
|
{
|
|
Thread.Sleep(VisualStudioProcessTimeout);
|
|
}
|
|
</pre>
|
|
<p>There are several obstacles on implementing the DTE approach.</p>
|
|
<p>First of all, we need to ensure that Visual Studio is not running during the
|
|
installation - this is because we want messages sent to Visual Studio instance
|
|
will arrive in the "invisible" one ran from our code and not the one which the
|
|
user have currently opened.</p>
|
|
<p>Similarly, we would like to wait a while until the instance terminates after
|
|
installation. This is necessary when integrating with multiple versions of
|
|
Visual Studio when just a single instance have to be running at a time. Doing two
|
|
installations too quickly in succession may cause the previous one to fail
|
|
because a Visual Studio instance is still running.</p>
|
|
<p>The communication between our code and Visual Studio is mediated by OLE
|
|
message filter which needs to be implemented. You can take a look on <strong>
|
|
DteToolboxInstaller</strong> (see below) source code, where is a working installer
|
|
implemented that uses this approach.</p>
|
|
<h3>Updating and Removing</h3>
|
|
<p>Since we have full control over the Toolbox with this approach, updating or
|
|
removing items/tabs is done with the corresponding DTE objects.</p>
|
|
<h3>Automatic Integration with DTE using DteToolboxInstaller</h3>
|
|
<p>I made a simple command-line application called <strong>DteToolboxInstaller</strong>
|
|
which does all the necessary steps and solves the deals with the discussed
|
|
obstacles. The usage is simple:</p>
|
|
<pre>DteToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]</pre>
|
|
<p>For example, if you like to install SampleControl.dll in Visual Studio 2012
|
|
Toolbox, just call:</p>
|
|
<pre>DteToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll</pre>
|
|
<p>You can use quotes for the last two parameters if they contain spaces.</p>
|
|
<p>The <strong>DteToolboxInstaller</strong> project is contained in sample
|
|
source code.</p>
|
|
<h2><a name="integration-vsi">7. Toolbox Integration using VSI Packages</a></h2>
|
|
<p>Let's consider you don't have a custom installer and want to distribute your
|
|
components in some kind of simple extension package that Visual Studio
|
|
understands.</p>
|
|
<p>Visual Studio contains an installer for so called VSI packages that will
|
|
do the integration work for you. If you have Visual Studio installed, the .VSI
|
|
extension is already associated with the Visual Studio Content Installer.</p>
|
|
<h3>Creating the VSI Package</h3>
|
|
<p>I have created an empty folder and copied <strong>SampleControl.dll</strong> in
|
|
it. All that is needed to make a VSI package is to create a .VSCONTENT file,
|
|
which is simply a XML file satisfying
|
|
<a href="http://msdn.microsoft.com/en-us/library/aa992029.aspx">Visual Studio Content Installer schema</a>:</p>
|
|
<pre>
|
|
<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">
|
|
<Content>
|
|
<FileName>SampleControl.dll</FileName>
|
|
<DisplayName>SampleControl</DisplayName>
|
|
<Description>ComponentOwl.com SampleControl</Description>
|
|
<FileContentType>Toolbox Control</FileContentType>
|
|
<ContentVersion>2.0</ContentVersion>
|
|
</Content>
|
|
</VSContent>
|
|
</pre>
|
|
<p>The content is readable and pretty straightforward. The <strong>
|
|
ContentVersion</strong> element can contain either "1.0" (support for Visual
|
|
Studio 2005, 2008 and 2010) or "2.0" (support for Visual Studio 2008, 2010,
|
|
2012, 2013).</p>
|
|
<p>Now we zip the two files and rename extension of the archive to .VSI. We
|
|
should end up with the following three files:</p>
|
|
<p><img height="74" src="../images/articles/vs-toolbox-integration/files-vsi.png" width="631" /></p>
|
|
<p>If you double-click the SampleControl.vsi, the Visual Studio
|
|
Content Installer opens up. You can start the installer from command line as
|
|
well:</p>
|
|
<pre>32-bit OS: C:\Program Files\Common Files\Microsoft Shared\MSEnv\VSContentInstaller.exe SampleControl.vsi
|
|
64-bit OS: C:\Program Files (x86)\Common Files\Microsoft Shared\MSEnv\VSContentInstaller.exe SampleControl.vsi</pre>
|
|
<p>The installer have a form o wizard:</p>
|
|
<p><img height="282" src="../images/articles/vs-toolbox-integration/vsi-installer-default.png" width="317" /></p>
|
|
<h3>Signing the VSI Package</h3>
|
|
<p>By default, the VSI package is not signed. This causes showing: "<strong>Publisher:
|
|
Unknown</strong>" label on the first page of the installation wizard and an unpleasant
|
|
dialog box later on:</p>
|
|
<p><img height="282" src="../images/articles/vs-toolbox-integration/vsi-installer-unsigned.png" width="317" /></p>
|
|
<p>To avoid this, you need to digitally sign the VSI package. Of course, you
|
|
have to own a digital certificate (usually an X.509 certificate stored in .PFX
|
|
file).</p>
|
|
<p>Because we cannot sign ZIP files, we need to convert the .VSI file (which is
|
|
actually a ZIP archive with just an altered extension) to self-extracting archive that the Visual Studio Content
|
|
Installer recognizes. There is a tool called <strong>MakeZipExe</strong>
|
|
to do this task:</p>
|
|
<pre>MakeZipExe.exe -zipfile:SampleControl.vsi -output:SampleControl-unsigned.vsi -overwrite</pre>
|
|
<p>The <strong>MakeZipExe</strong> tool is located at Visual Studio's binary
|
|
folder:</p>
|
|
<pre>c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MakeZipExe.exe</pre>
|
|
<p>The second step is signing the .EXE file using <strong>signtool.exe</strong>.
|
|
You can find <strong>signtool.exe</strong> in Microsoft Windows SDK, i.e.:</p>
|
|
<pre>c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe</pre>
|
|
<p>Here is a sample usage of <strong>signtool.exe</strong>:</p>
|
|
<pre>signtool.exe sign /du "http://www.componentowl.com/sample-control" /f certificate.pfx /p abc123 /t "http://timestamp.comodoca.com/authenticode" "SampleControl-signed.vsi"</pre>
|
|
<p>When signed, the "<strong>Publisher</strong>" and "<strong>Information URL</strong>" labels are filled in the
|
|
installer and no dialog box appears. The benefit of signing is obvious - your
|
|
users will know they are installing trusted, possibly high-quality software and there
|
|
is a higher chance of your software being used more widely (for example, the
|
|
government sector usually require such certified software).</p>
|
|
<p>You can also add an EULA to your VSI package. This can be done by adding a
|
|
comment metadata in the archive by ZIP archiver that supports such feature (e.g.
|
|
<a href="http://www.winzip.com">WinZip</a>).</p>
|
|
<h3>Uninstalling the Control from Toolbox</h3>
|
|
<p>As far as I know, the control cannot be removed from the Toolbox
|
|
programmatically. You need to delete the control's DLL located at</p>
|
|
<pre>c:\Users\<user>\Documents\Visual Studio 2010\Controls\</pre>
|
|
<p>the same should be done for every version of Visual Studio installed.</p>
|
|
<p>In Visual Studio, right-click on Toolbox and select "Reset Toolbox". The
|
|
component will not be found and disappear. Similarly, you can just
|
|
delete the control from the Toolbox or select "Choose Items..." from context
|
|
menu and untick the control there:</p>
|
|
<p><img height="274" src="../images/articles/vs-toolbox-integration/vsi-choose-items.png" width="673" /> </p>
|
|
<h3>Drawbacks of Using VSI Package</h3>
|
|
<p>One drawback of using VSI package is that the installer runs every version of
|
|
VS IDE you have installed and which is supported by the package. The form will
|
|
disappear eventually, but it lowers user experience.</p>
|
|
<p>Another drawback is that when you want to update your control, the installer
|
|
offers whether to rename, replace or skip the file (e.g. SampleControl.dll). User have to decide to
|
|
update, which also slows down installation and requires user interaction.</p>
|
|
<p>You also cannot specify custom Toolbox tab. All controls are installed under
|
|
"<strong>My Controls</strong>" tab:</p>
|
|
<p><img height="318" src="../images/articles/vs-toolbox-integration/toolbox-vsi.png" width="165" /></p>
|
|
<h2><a name="integration-vspackage">8. Toolbox Integration using VSPackages</a></h2>
|
|
<p>This approach brings full control over the integration and other benefits. The VSPackages are loaded on-demand, so
|
|
the integration process won't slow down a custom installer.</p>
|
|
<p>Although VSPackage and our sample control can be packed within the same
|
|
assembly, we will create a separate Visual Studio Package project.</p>
|
|
<p>When user opens Toolbox in VS for the first time after installation, the IDE
|
|
will look in registry for any registered packages and load them (if not loaded
|
|
previously).</p>
|
|
<h3>Creating VSPackage Project</h3>
|
|
<p>We would like to have our VSPackage compatible with VS 2010, 2012
|
|
and 2013, so we will work in Visual Studio 2010.</p>
|
|
<p>Select "File - New - Project.." (Control+Shift+N) and
|
|
select the "<strong>Visual Studio Package</strong>" template:</p>
|
|
<p><img height="450" src="../images/articles/vs-toolbox-integration/template-vspackage.png" width="825" /> </p>
|
|
<p>This will start a "Visual Studio Package Wizard":</p>
|
|
<p><img height="197" src="../images/articles/vs-toolbox-integration/vspackage-wizard-1.png" width="258" /></p>
|
|
<p>You can leave most options in the wizard on defaults. Leave all the check boxes unchecked
|
|
on "Page 3 of 7" and "Page 7 of 7":</p>
|
|
<p><img height="197" src="../images/articles/vs-toolbox-integration/vspackage-wizard-2.png" width="258" /></p>
|
|
<p><img height="197" src="../images/articles/vs-toolbox-integration/vspackage-wizard-3.png" width="258" /></p>
|
|
<p>Now we will take a look on the generated files. Open the <strong>Guids.cs</strong>
|
|
file:</p>
|
|
<pre>
|
|
// Guids.cs
|
|
// MUST match guids.h
|
|
using System;
|
|
|
|
namespace ComponentOwl.ToolboxIntegration
|
|
{
|
|
static class GuidList
|
|
{
|
|
<strong>public const string GuidSampleVSPackagePkgString = "00000000-8fdf-48b6-98f8-4ff21a3a4def";</strong>
|
|
public const string GuidSampleVSPackageCmdSetString = "def6519d-5ace-4062-95d6-4ee43f4a5de9";
|
|
|
|
public static readonly Guid GuidSampleVSPackageCmdSet = new Guid(GuidSampleVSPackageCmdSetString);
|
|
};
|
|
}
|
|
</pre>
|
|
<p>Here are the <a href="http://en.wikipedia.org/wiki/GUID">GUIDs</a> that
|
|
uniquely identify your package. I have edited the first four hex digits of
|
|
package identifier to "00000000" so that we can find it more easily later. This is
|
|
just for purpose of convenience in our sample project. Always use randomly generated GUID
|
|
in a real-world application. Visual Studio will generate a new GUID
|
|
whenever you create a new VSPackage project.</p>
|
|
<p>You can also generate new GUIDs any time, for example using
|
|
<a href="http://www.guidgenerator.com/">online GUID
|
|
generator</a> or <strong>guidgen.exe</strong> utility from Windows SDK. When these numbers are changed, your package will be different from
|
|
Visual Studio's point of view.</p>
|
|
<p>Another important file here is <strong>source.extension.vsixmanifest</strong>.
|
|
If you double-click on the file in Solution Explorer, the VSIX Manifest Designer
|
|
will show up:</p>
|
|
<p><img height="347" src="../images/articles/vs-toolbox-integration/vsix-manifest-designer.png" width="454" /></p>
|
|
<p>Not all the fields are mandatory, but I will fill all of them nevertheless:</p>
|
|
<ul class="common">
|
|
<li><strong>ID</strong> - Unique product "Identity" - the ID is limited to
|
|
100 characters and the recommended format is "Company.Product.Feature.Name".
|
|
We can leave the VSPackage's GUID here.</li>
|
|
<li><strong>Product Name</strong> - This field is used for Toolbox Tab name,
|
|
so I will put "Component Owl Controls" here.</li>
|
|
<li><strong>Author</strong> - Your name or company name -
|
|
"ComponentOwl.com", for example.</li>
|
|
<li><strong>Version</strong> - This is version of the package and its
|
|
contents. The format is same as for assembly versions:
|
|
Major.Minor.Build.Revision. I will put "1.4.0.128" here.</li>
|
|
<li><strong>Description</strong> - Speaks for itself.</li>
|
|
<li><strong>Locale</strong> - Language for the package.</li>
|
|
<li><strong>Supported VS Editions</strong> - Here you can specify which
|
|
editions of Visual Studio 2010 you would like to support. Of course, it can
|
|
support VS 2012/2013 as well, but for now I will just check Ultimate, Premium and
|
|
Professional editions.</li>
|
|
<li><strong>Supported Framework Runtime</strong> - Minimum and maximum .NET
|
|
Framework Runtime versions your extension supports. Since my component will
|
|
support 4.0 and 4.5 runtime, I will put 4.0 and 4.5 here.</li>
|
|
</ul>
|
|
<h3>Adding Support for Visual Studio 2012/2013</h3>
|
|
<p>We have specified supported Visual Studio Editions in VSIX Manifest Designer,
|
|
through the "Visual Studio Version and Edition" dialog box:</p>
|
|
<p><img height="220" src="../images/articles/vs-toolbox-integration/vs-editions-dialog.png" width="238" /></p>
|
|
<p>As you can see, only Visual Studio 2010 is supported here because VSIX is new
|
|
to 2010 and of course VS 2010 does not know about 2012/2013. We have to <strong>
|
|
source.extensions.vsixmanifest file</strong> for manual editing. Select the file
|
|
in Solution Explorer and press F7 (View Code):</p>
|
|
<pre>
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
|
|
<Identifier Id="aaaaaaaa-8fdf-48b6-98f8-4ff21a3a4def">
|
|
<Name>SampleVsPackage</Name>
|
|
<Author>ComponentOwl.com</Author>
|
|
<Version>1.0</Version>
|
|
<Description xml:space="preserve">Information about my package</Description>
|
|
<Locale>1033</Locale>
|
|
<InstalledByMsi>false</InstalledByMsi>
|
|
<SupportedProducts>
|
|
<strong> <VisualStudio Version="10.0">
|
|
<Edition>Ultimate</Edition>
|
|
<Edition>Premium</Edition>
|
|
<Edition>Pro</Edition>
|
|
</VisualStudio></strong>
|
|
</SupportedProducts>
|
|
<SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.5" />
|
|
</Identifier>
|
|
<References>
|
|
<Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
|
|
<Name>Visual Studio MPF</Name>
|
|
</Reference>
|
|
</References>
|
|
<Content>
|
|
<VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
|
|
</Content>
|
|
</Vsix>
|
|
</pre>
|
|
<p>Take a look on the <strong>Vsix/Identifier/SupportedProducts/VisualStudio</strong>
|
|
element (highlighted in bold). Copy and paste this element and modify <strong>
|
|
Version</strong> attribute on the second one to "11.0":</p>
|
|
<pre>
|
|
<VisualStudio Version="11.0">
|
|
<Edition>Ultimate</Edition>
|
|
<Edition>Premium</Edition>
|
|
<Edition>Pro</Edition>
|
|
</VisualStudio>
|
|
</pre>
|
|
<p>The edition tags are valid for version 11.0 because Visual Studio 2012
|
|
template generates the same edition names.</p>
|
|
<h3>Writing Package Code</h3>
|
|
<p>Now we will take a look on the VSPackage code itself. Open the <strong>
|
|
SampleVSPackage.cs</strong>
|
|
file. I kept only the necessary code and added the <strong>ProvideToolboxItems</strong> attribute:</p>
|
|
<pre>
|
|
[PackageRegistration(UseManagedResourcesOnly = true)]
|
|
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
|
|
[Guid(GuidList.guidSampleVsPackagePkgString)]
|
|
<strong>[ProvideToolboxItems(1)]</strong>
|
|
public sealed class SampleVsPackage : Package
|
|
{
|
|
}
|
|
</pre>
|
|
<p>Our VSPackage implementation inherits from <strong>
|
|
Microsoft.VisualStudio.Shell.Package</strong> class and is decorated by three
|
|
attributes:</p>
|
|
<ul class="common">
|
|
<li><strong>PackageRegistrationAttribute</strong> - Specifies that package
|
|
registration tool should look for additional attributes (will be discussed
|
|
later).</li>
|
|
<li><strong>InstalledProductRegistrationAttribute</strong> - Provides
|
|
information for the Visual Studio splash screen and About box.</li>
|
|
<li><strong>GuidAttribute</strong> - Provides custom GUID for the class
|
|
because automatic GUID is undesirable here (Visual Studio need to be able to trace our
|
|
package by its unique ID).</li>
|
|
<li><strong>ProvideToolboxItemsAttribute</strong> - Specifies that the
|
|
package provides toolbox items. There are various uses of VSPackages, but we
|
|
are interested in intalling controls to Visual Studio Toolbox, hence this
|
|
attribute.</li>
|
|
</ul>
|
|
<p>The strings "#110" and "#112" in <strong>
|
|
InstalledProductRegistrationAttribute</strong> refer to keys in <strong>
|
|
VSPackage.resx</strong>. You can open this file and edit package name and
|
|
description there:</p>
|
|
<p><img height="92" src="../images/articles/vs-toolbox-integration/vspackage-resx-designer.png" width="422" /></p>
|
|
<p>Now we write methods within <strong>SampleVsPackage</strong> class that work with the Toolbox:</p>
|
|
<pre>
|
|
private const string ComponentFile = "SampleControl.dll";
|
|
private const string TabName = "Component Owl";
|
|
|
|
private void InstallToolboxItems()
|
|
{
|
|
IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
|
|
|
|
foreach (ToolboxItem item in ToolboxService.GetToolboxItems(GetAssemblyName()))
|
|
{
|
|
toolboxService.AddToolboxItem(item, TabName);
|
|
}
|
|
}
|
|
|
|
private void RemoveToolboxItems()
|
|
{
|
|
IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
|
|
|
|
foreach (ToolboxItem item in ToolboxService.GetToolboxItems(GetAssemblyName()))
|
|
{
|
|
toolboxService.RemoveToolboxItem(item);
|
|
}
|
|
}
|
|
|
|
private AssemblyName GetAssemblyName()
|
|
{
|
|
string pathAssembly = String.Concat(
|
|
Path.GetDirectoryName(GetType().Assembly.Location),
|
|
Path.DirectorySeparatorChar,
|
|
ComponentFile);
|
|
|
|
return AssemblyName.GetAssemblyName(pathAssembly);
|
|
}
|
|
</pre>
|
|
<p>The method names <strong>InstallToolboxItems</strong> and <strong>
|
|
RemoveToolboxItems</strong>
|
|
speak for themselves. Both methods look for SampleControl.dll in the same
|
|
location as the VSPackage's assembly. They get all toolbox items from the
|
|
assembly and either put them under "Component Owl" tab or remove them.</p>
|
|
<p>The <strong>ToolboxService</strong> class comes from <strong>
|
|
System.Drawing.Design</strong> and we need to add reference to this asssembly in
|
|
order to use <strong>ToolboxService</strong>.</p>
|
|
<h3>Building the Package</h3>
|
|
<p>Before building the <strong>SampleVsPackage</strong> project, open project
|
|
properties, find the VSIX tab and uncheck all the options:</p>
|
|
<p><img height="225" src="../images/articles/vs-toolbox-integration/vsix-options.png" width="664" /></p>
|
|
<p>Finally, build the project. Just two files, <strong>SampleVsPackage.dll</strong>
|
|
and <strong>SampleVsPackage.pdb</strong>, should be generated.</p>
|
|
<h3>Registering the Package</h3>
|
|
<p>Until the package can be loaded by Visual Studio, it needs to be
|
|
<a href="http://msdn.microsoft.com/en-us/library/bb187332(v=vs.80).aspx">registered</a>.
|
|
The registration is simply writing specific keys into Windows Registry.</p>
|
|
<p>To do that, find the <strong>Package Registration Utility</strong> (RegPkg.exe). It should be
|
|
located in Visual Studio SDK directory, e.g.:</p>
|
|
<pre>32-bit OS: c:\Program Files\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Tools\Bin\RegPkg.exe
|
|
64-bit OS: c:\Program Files (x86)\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Tools\Bin\RegPkg.exe</pre>
|
|
<p>You can copy the tool where it suits you.</p>
|
|
<p>Here is a sample usage of RegPkg:</p>
|
|
<pre>32-bit OS: RegPkg.exe /root:SOFTWARE\Microsoft\VisualStudio\11.0 /codebase SampleVsPackage.dll
|
|
64-bit OS: RegPkg.exe /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0 /codebase SampleVsPackage.dll</pre>
|
|
<p>This will write package registration information into the Windows Registry,
|
|
hence registers the package. Similar call have to be done by your custom installer in
|
|
order to register the package.</p>
|
|
<p>Instead of writing into registry, RegPkg.exe can gereate a REG file (several
|
|
other formats are available) so that you can write package information into
|
|
registry using the file. To do that, use <strong>/regfile</strong> parameter:</p>
|
|
<pre>32-bit OS: RegPkg.exe /root:SOFTWARE\Microsoft\VisualStudio\11.0 /regfile:SampleVsPackage.ref /codebase SampleVsPackage.dll
|
|
64-bit OS: RegPkg.exe /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0 /regfile:SampleVsPackage.ref /codebase SampleVsPackage.dll</pre>
|
|
<p>This creates <strong>SampleVsPackge.reg</strong> file you can use any time
|
|
later instead of RegPkg.exe itself.</p>
|
|
<p>There are two other options for specifying how the package will be registered:
|
|
<strong>codebase</strong> and <strong>assembly</strong>. When <strong>/codebase</strong>
|
|
parameter is used (as in the sample above), the registry will point to the location on disk where your
|
|
package is located (see
|
|
<a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.codebase.aspx">
|
|
Assembly.CodeBase</a> property for more information).</p>
|
|
<p>Another option is the <strong>/assembly</strong> parameter - this assumbes
|
|
that your VSPackage assembly is located in GAC (Global Assembly Cache). See
|
|
section <em>Installing the Control in GAC</em> for more information.</p>
|
|
<p>You can check out the registry after the package registration:</p>
|
|
<p><img height="220" src="../images/articles/vs-toolbox-integration/registry-package.png" width="991" /></p>
|
|
<h3>Package Registration for Visual Studio 2012/2013</h3>
|
|
<p>Regrettably, simply registering package is not enough for Visual Studio 2012/2013 to load
|
|
it (see this
|
|
<a href="http://blogs.msdn.com/b/dsvst/archive/2012/10/08/your-vs-package-may-not-load-after-porting-it-to-vs-2012.aspx">
|
|
blog post</a>). Because of performance optimizations, VS developers removed
|
|
feature that looks for changes in VS registry root and thus we need to call</p>
|
|
<pre>devenv.exe /Setup</pre>
|
|
<p>In order to finish package registration.</p>
|
|
<p>This call can be very time consuming since Visual Studio 2012/2013 goes through all
|
|
extensions and looks for changes. On the other hand, I tried running devenv.exe with /Setup
|
|
parameter on fresh install of Visual Studio 2012/2013 and it was instant. On older
|
|
installation, however, the operation took well over a minute (it behaves just
|
|
like Microsoft Windows, which progressively slows down during its lifetime).</p>
|
|
<p>We can speed things up by a little hack. One of the things the <strong>/Setup</strong>
|
|
does is copying registry keys from HKLM to Visual Studio's 11.0_Config hive (or 12.0_Config, respectively). We can just write registry under this key
|
|
instead of calling devenv.exe and avoid possibly lengthy operation.</p>
|
|
<p>The hive is located in <strong>
|
|
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config</strong>.</p>
|
|
<p>So let's open and edit the <strong>SampleVsPackage.reg</strong> file we have
|
|
generated using <strong>RegPkg.exe</strong> earlier. Here is the modified version where only the
|
|
registry root has been changed:</p>
|
|
<pre>
|
|
REGEDIT4
|
|
|
|
[<strong>HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config</strong>\InstalledProducts\SampleVsPackage]
|
|
@="#110"
|
|
"Package"="{00000000-8fdf-48b6-98f8-4ff21a3a4def}"
|
|
"PID"="1.0"
|
|
"ProductDetails"="#112"
|
|
"LogoID"="#400"
|
|
[<strong>HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config</strong>\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
|
|
@="ComponentOwl.ToolboxIntegration.SampleVsPackage, SampleVsPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30782fc44cbe0af5"
|
|
"InprocServer32"="C:\\Windows\\SYSTEM32\\MSCOREE.DLL"
|
|
"Class"="ComponentOwl.ToolboxIntegration.SampleVsPackage"
|
|
"CodeBase"="C:\\projects\\articles\\2012-10-22 Visual Studio Toolbox Control Integration\\ToolboxIntegration\\SampleVsPackage\\bin\\Debug\\SampleVsPackage.DLL"
|
|
[<strong>HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config</strong>\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
|
|
[<strong>HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config</strong>\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}\Toolbox]
|
|
"Default Items"=dword:00000001
|
|
</pre>
|
|
<p>The highlighted parts have been edited.</p>
|
|
<p>So in addition to standard package registration, we also write in the
|
|
registry where Visual Studio 2012/2013 user config hive resides. This is sufficient
|
|
for our VSPackage to load.</p>
|
|
<p>However, this is really a hack - editing of user configuration in registry
|
|
may cause Visual Studio to not load your user settings and show up as when
|
|
running for the first time. I tried this hack on my machine and it worked, but
|
|
there may be some hidden glitches. If you want to follow standard procedure,
|
|
just call "<strong>devenv.exe /Setup</strong>".</p>
|
|
<h3>Loading VSPackage</h3>
|
|
<p>If you did all the previous steps, your package should load when you open
|
|
Windows Forms Designer and show Toolbox (Cotrol+Alt+X). You can notice your
|
|
package name displaying in status bar for a while, then SampleControl should show up in the
|
|
Toolbox under "Component Owl" tab:</p>
|
|
<p><img height="318" src="../images/articles/vs-toolbox-integration/toolbox-1.png" width="256" /></p>
|
|
<h3>Displaying Your Extension in VS About Box</h3>
|
|
<p>If you want information about your extension to be visible in Visual Studio
|
|
splash screen and About Box, implement <strong>IVsInstalledProduct</strong>
|
|
interface:</p>
|
|
<pre>
|
|
...
|
|
|
|
public sealed class SampleVsPackage : Package, IVsInstalledProduct
|
|
{
|
|
|
|
...
|
|
|
|
int IVsInstalledProduct.IdBmpSplash(out uint pIdBmp)
|
|
{
|
|
pIdBmp = 0;
|
|
return 0;
|
|
}
|
|
|
|
int IVsInstalledProduct.IdIcoLogoForAboutbox(out uint pIdIco)
|
|
{
|
|
pIdIco = 400;
|
|
return 0;
|
|
}
|
|
|
|
int IVsInstalledProduct.OfficialName(out string pbstrName)
|
|
{
|
|
pbstrName = "ComponentOwl SampleControl";
|
|
return 0;
|
|
}
|
|
|
|
int IVsInstalledProduct.ProductDetails(out string pbstrProductDetails)
|
|
{
|
|
pbstrProductDetails = "SampleControl control.\r\nFor more information see http://www.componentowl.com";
|
|
return 0;
|
|
}
|
|
|
|
int IVsInstalledProduct.ProductID(out string pbstrPID)
|
|
{
|
|
pbstrPID = "3.3.0.0";
|
|
return 0;
|
|
}
|
|
|
|
...
|
|
|
|
}
|
|
</pre>
|
|
<p>This code causes the component to show up in the list of "Installed Products"
|
|
in Visual Studio about box:</p>
|
|
<p><img height="295" src="../images/articles/vs-toolbox-integration/about-box.png" width="395" /></p>
|
|
<p>As for the splash screen, Visual Studio 2008 used to display extensions in
|
|
its splash screen, but later version do not:</p>
|
|
<p><img height="160" src="../images/articles/vs-toolbox-integration/splash-2008.png" width="264" />
|
|
<img height="184" src="../images/articles/vs-toolbox-integration/splash-2010.png" width="264" />
|
|
<img height="264" src="../images/articles/vs-toolbox-integration/splash-2012.png" width="202" /></p>
|
|
<h3>Troubleshooting Package Load Failures</h3>
|
|
<p>You may encounter this dialog when playing with packages:</p>
|
|
<p><img height="319" src="../images/articles/vs-toolbox-integration/package-load-failure.png" width="494" /></p>
|
|
<p>When you click "No", the package will be skipped later when loading packages.
|
|
You can re-enable loading all packages by running</p>
|
|
<pre>devenv.exe /ResetSkipPkgs</pre>
|
|
<p>To debug package load problem, you can do just what the dialog says. Run</p>
|
|
<pre>devenv.exe /log</pre>
|
|
<p>and then take a look on the <strong>ActivityLog.xml</strong> (path is shown
|
|
in the dialog). There you can find cause of the problem in one of the "<strong>entry</strong>"
|
|
elements:</p>
|
|
<pre>
|
|
...
|
|
<entry>
|
|
<record>106</record>
|
|
<time>2012/10/26 06:07:36.920</time>
|
|
<type>Error</type>
|
|
<source>VisualStudio</source>
|
|
<description>CreateInstance failed for package [ComponentOwl.ToolboxIntegration.SampleVSPackage, SampleVSPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=87379c2b0cde9bc3]</description>
|
|
<guid>{761F0CB7-64C1-4695-91D2-6E3C26C12314}</guid>
|
|
<hr>80070002</hr>
|
|
<errorinfo><strong>Could not load file or assembly 'file:///C:\projects\articles\2012-10-22 Visual Studio Toolbox Control Integration\ToolboxIntegration\SampleVSPackage\bin\SampleVSPackage.DLL' or one of its dependencies. The system cannot find the file specified.</strong></errorinfo>
|
|
</entry>
|
|
...
|
|
</pre>
|
|
<p>In this particular case, the problem was caused by changing output path from
|
|
"<strong>bin\SampleVSPackage.dll</strong>" to "<strong>bin\Debug\SampleVSPackage.dll</strong>"
|
|
so the file does not longer exist at the location for which it is registered.
|
|
The solution is to either change the location back or unregister the package
|
|
(i.e. remove the corresponding registry entries - the GUID is provided in the
|
|
log).</p>
|
|
<h3>Past Troubles with Package Load Keys</h3>
|
|
<p>The above problem with package load failure happened on Visual Studio 2005
|
|
and 2008 because a Package Load Key (PLK) had to be provided by the VSPackage.
|
|
The PLK is basically a hashcode computed from metadata about package (name,
|
|
author/company, version). The PLK had to be obtained from a website provided by
|
|
Microsoft.</p>
|
|
<p>I believe PLK caused many troubles and headaches to developers, including
|
|
myself.</p>
|
|
<p>This is no longer relevant for Visual Studio 2010 and newer (requirement for
|
|
PLKs removed), so we won't discuss this topic in more depth</p>
|
|
<h3>Update Control Already Installed in Toolbox</h3>
|
|
<p>Suppose we have already integrated SampleControl version 3.3.0.0 in the
|
|
Visual Sudio Toolbox:</p>
|
|
<p><img height="337" src="../images/articles/vs-toolbox-integration/toolbox-update-1.png" width="290" /></p>
|
|
<p>We would like to update this control to version 3.4.0.0.</p>
|
|
<p>First of all, we update assembly information of the <strong>SampleControl</strong>
|
|
project:</p>
|
|
<p><img height="405" src="../images/articles/vs-toolbox-integration/assembly-info.png" width="407" /></p>
|
|
<p>If we "deploy" (copy) SampleControl.dll to the folder with
|
|
SampleVsPackage.dll where it is registered, the SampleControl will no longer be
|
|
visible in Toolbox, because the control in Toolbox should still be 3.3.0.0 and
|
|
this version is no longer to be found.</p>
|
|
<p>You don't need to increment assembly version of the SampleVsPackage project,
|
|
but at least you have to increment parameter of the <strong>ProvideToolboxItems</strong> attribute:</p>
|
|
<pre>
|
|
[PackageRegistration(UseManagedResourcesOnly = true)]
|
|
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
|
|
[Guid(GuidList.guidSampleVsPackagePkgString)]
|
|
<strong>[ProvideToolboxItems(2)]</strong>
|
|
public sealed class SampleVsPackage : Package, IVsInstalledProduct
|
|
{
|
|
...
|
|
}
|
|
</pre>
|
|
<p>The package need to be re-registered (see section <em>Registering the Package</em>)
|
|
which will effectively update just the "Default Items" value in the Toolbox key:</p>
|
|
<p><img height="166" src="../images/articles/vs-toolbox-integration/registry-toolbox.png" width="720" /></p>
|
|
<p>This will cause Visual Studio to update your control in the Toolbox:</p>
|
|
<p><img height="337" src="../images/articles/vs-toolbox-integration/toolbox-update-2.png" width="287" /></p>
|
|
<h3>Remove Control from the Toolbox</h3>
|
|
<p>Now we would like to remove control from the Visual Studio Toolbox. This
|
|
step can be done by custom uninstaller.</p>
|
|
<p>One way to do that is to simply <em>unregister</em> the VSPackage using
|
|
RegPkg.exe:</p>
|
|
<pre>32-bit OS: RegPkg.exe /unregister /root:SOFTWARE\Microsoft\VisualStudio\10.0 SampleVsPackage.dll
|
|
64-bit OS: RegPkg.exe /First of all, we update assembly information of the unregisFirst of all, we update assembly information of the ter /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0 SampleVsPackage.dll</pre>
|
|
<p>You can also do this manually by simply removing the registry entry of the
|
|
corresponding package, e.g.:</p>
|
|
<pre>32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{a9696de6-e209-414d-bbec-a0506fb0e924}
|
|
64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{a9696de6-e209-414d-bbec-a0506fb0e924}</pre>
|
|
<p>On Visual Studio 2012/2013, the key need to be removed in user config registry
|
|
hive or call "devenv.exe /Setup" after removing the registry key in HKLM. For
|
|
more information, see section <em>Package Registration for Visual Studio 2012/2013</em>.</p>
|
|
<h2><a name="integration-vsix">9. Toolbox Integration using VSIX Packages</a></h2>
|
|
<p>Microsoft have removed most /po
|
|
f the drawbacks of VSI packages by introducing VSIX. The
|
|
price is that VSIX is a little bit more complicated and Visual Studio 2008 is no
|
|
longer supported.</p>
|
|
<p>There are two versions of VSIX Schema. Version 1.0 is what Visual Studio 2010
|
|
understand. There is also version 2.0 for Visual Studio 2012/2013. We want a VSIX
|
|
Package compatible with both, so we will work in Visual Studio 2010.</p>
|
|
<h3>Create a new Project from Template</h3>
|
|
<p>If you have Visual Studio 2010 SDK installed, you can create a new VSIX
|
|
package project with control from a template.</p>
|
|
<p>Select "File - New - Project.." (Control+Shift+N) and
|
|
then select the "<strong>Windows Forms Toolbox Control</strong>" or "<strong>WPF
|
|
Toolbox Control</strong>" template:</p>
|
|
<p><img height="450" src="../images/articles/vs-toolbox-integration/template-toolbox-control.png" width="823" /></p>
|
|
<p>The projects is basically a VSPackage wrapped in VSIX container after
|
|
build. The package assembly also contain the control class named <strong>
|
|
ToolboxControl</strong>.</p>
|
|
<p>There are three important files generated by the template:</p>
|
|
<ul class="common">
|
|
<li><strong>ProvideToolboxControlAttribute.cs</strong> - This is attribute
|
|
for ToolboxControl class. We will discuss it later.</li>
|
|
<li><strong>source.extension.vsixmanifest</strong> - This is manifest XML
|
|
file for our VSIX package. It contains all information about the package and
|
|
what it contains.</li>
|
|
<li><strong>ToolboxControl.cs</strong> - This is a sample control to be
|
|
installed in Visual Studio Toolbox.</li>
|
|
</ul>
|
|
<h3>Create a new Project from VSPackage</h3>
|
|
<p>We can also start with VSPackage like the one we have already created in
|
|
previous section. I will create a new VSPackage project (as in previous
|
|
chapter), name it <strong>SampleVsixPackage</strong> and configure it according
|
|
to "Windows Forms Toolbox Control" template to show you all the differences.</p>
|
|
<p>The basic configuration of <strong>source.extension.vsixmanifest</strong> is
|
|
the same as in previous chapter.</p>
|
|
<p>Project properties differs from VSPackage we have created earlier on the VSIX
|
|
tab, where we have the first two check boxes checked:</p>
|
|
<p><img height="225" src="../images/articles/vs-toolbox-integration/vsix-options.png" width="664" /></p>
|
|
<h3>Update the Manifest File</h3>
|
|
<p>Double-click on the <strong>source.extension.vsixmanifest</strong> file to
|
|
open up the <a href="http://msdn.microsoft.com/en-us/library/ee943167.aspx">VSIX Manifest Designer</a>:</p>
|
|
<p><img height="347" src="../images/articles/vs-toolbox-integration/vsix-manifest-designer.png" width="454" /></p>
|
|
<p>If you are not sure about some part of the form, please take a look on
|
|
section <em>Create VSPackage Project</em>, where the form is described in more
|
|
detail.</p>
|
|
<p>In addition to previous VSPackage project, I have also filled the following
|
|
optional boxes:</p>
|
|
<ul class="common">
|
|
<li><strong>License Terms</strong> - If you have EULA or other licence in
|
|
TXT or RTF format, you can browse for it.</li>
|
|
<li><strong>Icon</strong> - You can browse for an icon representing the
|
|
extension. It should be 32x32 pixels large, PNG, BMP, JPEG or ICO image
|
|
format.</li>
|
|
<li><strong>Preview Image</strong> - Thumbnail image representing the
|
|
extension. It should be 200x200 pixels large, PNG, BMP or JPEG image format.</li>
|
|
<li><strong>More Info URL</strong> - URL of a website containing more
|
|
information about the extension.</li>
|
|
<li><strong>Getting Started Guide</strong> - URL of a website with
|
|
documentation; you can also provide relative path to HTML file with the
|
|
local documentation.</li>
|
|
</ul>
|
|
<h3>Add Control</h3>
|
|
<p>Let's create a new WPF control within the <strong>SampleVsixPackage</strong>
|
|
project itself. I will name it <strong>SampleWpfControl</strong> to distinguish
|
|
it from <strong>SampleControl</strong> we have created earlier.</p>
|
|
<p>To ensure our control will show up in Toolbox of Visual Studio 2012/2013, we have
|
|
to decorate the <strong>SampleWpfControl</strong> class by <strong>
|
|
ProvideToolboxControlAttribute</strong>:</p>
|
|
<pre>
|
|
<strong>[ProvideToolboxControl("SampleWpfControl", true)]</strong>
|
|
public partial class SampleWpfControl : UserControl
|
|
{
|
|
...
|
|
}
|
|
</pre>
|
|
<p>You also have to provide implementation of the attribute class:</p>
|
|
<pre>
|
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
|
[System.Runtime.InteropServices.ComVisibleAttribute(false)]
|
|
public sealed class ProvideToolboxControlAttribute : RegistrationAttribute
|
|
{
|
|
private const string ToolboxControlsInstallerPath = "ToolboxControlsInstaller";
|
|
|
|
public ProvideToolboxControlAttribute(string name, bool isWpfControls)
|
|
{
|
|
if (name == null)
|
|
{
|
|
throw new ArgumentException("name");
|
|
}
|
|
|
|
this.Name = name;
|
|
this.IsWpfControls = isWpfControls;
|
|
}
|
|
|
|
private bool IsWpfControls { get; set; }
|
|
private string Name { get; set; }
|
|
|
|
public override void Register(RegistrationAttribute.RegistrationContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw new ArgumentNullException("context");
|
|
}
|
|
|
|
using (Key key = context.CreateKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
|
|
ToolboxControlsInstallerPath,
|
|
context.ComponentType.Assembly.FullName)))
|
|
{
|
|
key.SetValue(String.Empty, this.Name);
|
|
key.SetValue("Codebase", context.CodeBase);
|
|
if (this.IsWpfControls)
|
|
{
|
|
key.SetValue("WPFControls", "1");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public override void Unregister(RegistrationAttribute.RegistrationContext context)
|
|
{
|
|
if (context != null)
|
|
{
|
|
context.RemoveKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
|
|
ToolboxControlsInstallerPath,
|
|
context.ComponentType.AssemblyQualifiedName));
|
|
}
|
|
}
|
|
}
|
|
</pre>
|
|
<p>This code is generated if you create project from template.</p>
|
|
<p>The project in Solution Explorer should look like this:</p>
|
|
<p>
|
|
<img height="348" src="../images/articles/vs-toolbox-integration/solution-explorer-samplevsixpackage.png" width="260" /></p>
|
|
<h3>Adding Controls from Other Projects</h3>
|
|
<p>What if we would like to use <strong>SampleControl.dll</strong> as in the VSI
|
|
package scenario?</p>
|
|
<p>Of course, we can click "Add Content" in the VSIX Manifest designer and
|
|
simply add "Toolbox Control" content from other project:</p>
|
|
<p><img height="338" src="../images/articles/vs-toolbox-integration/vsix-designer-add-content.png" width="469" /></p>
|
|
<p>However, this is possible only if the <strong>SampleControl</strong> project
|
|
itself is a package project!</p>
|
|
<p>Lucklily, since the VSIX package is still just a ZIP archive, we can take a
|
|
look on how to add such external DLLs to it manually.</p>
|
|
<h3>Setting Up VSIX Installer</h3>
|
|
<p>The VSIX Installer tool (<strong>VsixInstaller.exe</strong>) is located in
|
|
Visual Studio's binary folder:</p>
|
|
<pre>32-bit OS: c:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe
|
|
64-bit OS: c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe</pre>
|
|
<p>You can hit F6 and Visual Studio will build your project to create <strong>
|
|
SampleVsixPackage.vsix</strong> file. This is our VSIX package.</p>
|
|
<p>The VSIX Installer should be associated with the .VSIX file extension, so it is
|
|
usually possible
|
|
to just double-click on the file and see the VSIX installer.</p>
|
|
<p>The installation can fail in the very first step:</p>
|
|
<p><img height="293" src="../images/articles/vs-toolbox-integration/vsix-installer-1.png" width="450" /></p>
|
|
<p>This problem appears if you have invalid manifest file. If this happen, open
|
|
<strong>source.extension.vsixmanifest</strong> and fill in all missing data.
|
|
Furthermore, you can check if the XML is valid according to
|
|
<a href="http://msdn.microsoft.com/en-us/library/dd393700(v=vs.100).aspx">VSIX Extension
|
|
Schema</a>.</p>
|
|
<p>Now we are able to rebuild and run the VSIX installer again:</p>
|
|
<p><img height="338" src="../images/articles/vs-toolbox-integration/vsix-installer-2.png" width="450" /></p>
|
|
<h3>Make the VSIX Package Compatible with Visual Studio 2012/2013</h3>
|
|
<p>To make our VSIX package working with Visual Studio 2012 and newer, we need
|
|
to manually update the manifest file. Select the <strong>
|
|
source.extension.vsixmanifest</strong> file and press F7 (View Code):</p>
|
|
<pre>
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
|
|
<Identifier Id="ComponentOwl.ToolboxControl.Express">
|
|
<Name>Component Owl</Name>
|
|
<Author>ComponentOwl.com</Author>
|
|
<Version>1.0</Version>
|
|
<Description xml:space="preserve">Windows Forms Toolbox Control</Description>
|
|
<Locale>1033</Locale>
|
|
<MoreInfoUrl>http://www.componentowl.com/toolbox-control</MoreInfoUrl>
|
|
<License>license.rtf</License>
|
|
<GettingStartedGuide>http://www.componentowl.com/documentation/toolbox-control</GettingStartedGuide>
|
|
<Icon>icon.png</Icon>
|
|
<PreviewImage>overview.jpg</PreviewImage>
|
|
<SupportedProducts>
|
|
<VisualStudio Version="10.0">
|
|
<Edition>Ultimate</Edition>
|
|
<Edition>Premium</Edition>
|
|
<Edition>Pro</Edition>
|
|
</VisualStudio>
|
|
<strong> <VisualStudio Version="11.0">
|
|
<Edition>Ultimate</Edition>
|
|
<Edition>Premium</Edition>
|
|
<Edition>Pro</Edition>
|
|
</VisualStudio></strong>
|
|
<strong> <VisualStudio Version="12.0">
|
|
<Edition>Ultimate</Edition>
|
|
<Edition>Premium</Edition>
|
|
<Edition>Pro</Edition>
|
|
</VisualStudio></strong>
|
|
</SupportedProducts>
|
|
<SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="5.0" />
|
|
</Identifier>
|
|
<References />
|
|
<Content>
|
|
<ToolboxControl>|%CurrentProject%;PkgdefProjectOutputGroup|</ToolboxControl>
|
|
</Content>
|
|
</Vsix>
|
|
</pre>
|
|
<p>The bolded text have been added. I have simply added a new <strong>
|
|
VisualStudio</strong> element with higher version and all the editions (they are
|
|
relevant for VS 2012 and 2013 as its own template also generates these).</p>
|
|
<p>The VSIX installer will show Visual Studio 2012 options as
|
|
well after this update (if installed, of course):</p>
|
|
<p><img height="354" src="../images/articles/vs-toolbox-integration/vsix-installer-3.png" width="450" /></p>
|
|
<p>Please note that Visual Studio 2012/2013 also works with 2.0 version of the
|
|
schema, so if you create VSIX package in Visual Studio 2012/2013, it won't be
|
|
compatible with 2010. The solution is hence to use 1.0 version of the schema
|
|
and add support for newer Visual Studio as described earlier.</p>
|
|
<p>A great advantage over VSI package is that installation of Toolbox control is
|
|
really fast with VSIX.</p>
|
|
<p>Regrettably, the control won't show up in Visual Studio 2012/2013 Toolbox in its
|
|
default configuration. You need to enable loading-per user extensions (this
|
|
option is enabled by default in Visual Studio 2010):</p>
|
|
<p><img height="199" src="../images/articles/vs-toolbox-integration/vsix-per-user-extensions.png" width="757" /></p>
|
|
<h3>Signing the VSIX Package</h3>
|
|
<p>Unlike older VSI package, there is no nag screen when the package is not
|
|
signed. Instead, a label appears informing user that the package is not
|
|
signed.</p>
|
|
<p>To sign a VSIX package, we need <strong>PackageSignatureManager</strong> from
|
|
<strong>System.IO.Packaging</strong> (<strong>WindowsBase.dll</strong>). I made a simple command-line application called <strong>SignVsix</strong> (you can
|
|
find it in sample source code) that takes three arguments (VSIX file path, PFX
|
|
certificate path and password for the certificate):</p>
|
|
<pre>
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO.Packaging;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
internal class Program
|
|
{
|
|
private static void Main(string[] args)
|
|
{
|
|
// first argument - path to VSIX package
|
|
string paramPathPackage = args[0].Replace("\"", "");
|
|
// second argument - path to PFX certificate
|
|
string paramPathCertificate = args[1].Replace("\"", "");
|
|
// third argument - password for the certificate
|
|
string paramPassword = args[2];
|
|
|
|
// open VSIX package
|
|
Package package = Package.Open(paramPathPackage, FileMode.Open);
|
|
|
|
// load certificate
|
|
byte[] certificate = File.ReadAllBytes(paramPathCertificate);
|
|
|
|
// sign all parts of the package
|
|
var signatureManager = new PackageDigitalSignatureManager(package)
|
|
{
|
|
CertificateOption = CertificateEmbeddingOption.InSignaturePart
|
|
};
|
|
|
|
List<Uri> partsToSign = new List<Uri>();
|
|
|
|
foreach (PackagePart packagePart in package.GetParts())
|
|
{
|
|
partsToSign.Add(packagePart.Uri);
|
|
}
|
|
|
|
partsToSign.Add(PackUriHelper.GetRelationshipPartUri(signatureManager.SignatureOrigin));
|
|
partsToSign.Add(signatureManager.SignatureOrigin);
|
|
partsToSign.Add(PackUriHelper.GetRelationshipPartUri(new Uri("/", UriKind.RelativeOrAbsolute)));
|
|
|
|
try
|
|
{
|
|
signatureManager.Sign(partsToSign, new X509Certificate2(certificate, paramPassword));
|
|
}
|
|
catch (CryptographicException cryptographicException)
|
|
{
|
|
Console.WriteLine("Signing failed: {0}", cryptographicException.Message);
|
|
}
|
|
}
|
|
}
|
|
</pre>
|
|
<p>The usage is very simple:</p>
|
|
<pre>SignVsix.exe SampleVsixPackage.vsix certificate.pfx abc123</pre>
|
|
<p>When the file is signed, VSIX Installer shows label "Digital Signature:
|
|
<Author Name>" on the first page:</p>
|
|
<p><img height="354" src="../images/articles/vs-toolbox-integration/vsix-signed.png" width="450" /></p>
|
|
<h3>Dissecting the VSIX Package</h3>
|
|
<p>If you look on the project references, you can see reference to <strong>
|
|
Microsoft.VisualStudio.Shell.Immutable.10</strong>. This reference points to
|
|
Visual Studio 2010 SDK and we cannot expect this dependency present on end-user's machine. This
|
|
library contains <strong>ProvideToolboxControlAttribute</strong> class, which is
|
|
used by our <strong>ToolboxControl</strong>.</p>
|
|
<p>Since a software development company may want to develop many components, it would be nice to have an
|
|
universal VSIX package which can be adjusted for <em>any</em> control.</p>
|
|
<p>Let's take a look on the <strong>ToolboxControl.vsix</strong>. It is simply a
|
|
ZIP archive containing the manifest, resources, ToolboxControl binary and a
|
|
<strong>ToolboxControl.pkgdef</strong> file. If we look through all its content,
|
|
we easily generate our own VSIX packages on demand, even without Visual Studio.
|
|
There should also be a programmatic way on generating VSIX packages using
|
|
classes from System.IO.Packaging.</p>
|
|
<h3>Update Toolbox Control via VSIX Package</h3>
|
|
<p>If you made changes to your control and want to re-install the package, an
|
|
error message appear:</p>
|
|
<p><img height="171" src="../images/articles/vs-toolbox-integration/vsix-already-installed.png" width="433" /></p>
|
|
<p>In order to provide an update, you need to increment version number in the
|
|
VSIX manifest:</p>
|
|
<p><img height="269" src="../images/articles/vs-toolbox-integration/vsix-increment-version.png" width="364" /></p>
|
|
<p>You can also increment version number in the Package class attribute, but
|
|
this is not necessary for the VSIX to perform update:</p>
|
|
<pre>
|
|
[InstalledProductRegistration("#110", "#112", <strong>"2.0"</strong>, IconResourceID = 400)]
|
|
[Guid(GuidList.guidSampleVsixPackagePkgString)]
|
|
public sealed class SampleVsixPackage : Package
|
|
{
|
|
...
|
|
}
|
|
</pre>
|
|
<p>Of course, you can also increment version of the assembly.</p>
|
|
<h3>Uninstall the VSIX Package</h3>
|
|
<p>The VSIX Installer can be used to uninstall control from the Toolbox via
|
|
/uninstall parameter followed by package ID (the constant located in <strong>
|
|
Guids.cs</strong>: <strong>GuidList.guidSampleVsixPackagePkgString</strong>):</p>
|
|
<pre>VSIXInstaller.exe /uninstall:e3dfd099-d0ab-4b8e-b26d-639032c29ad9</pre>
|
|
<p>It is also possible to uninstall VSIX Package manually using <strong>
|
|
Extension Manager</strong> (Tools - Extension Manager...). In Visual Studio
|
|
2012/2013, the corresponding dialog is called <strong>Extensions and Updates</strong>
|
|
(Tools - Extensions and Updates...).</p>
|
|
<p><img height="244" src="../images/articles/vs-toolbox-integration/vsix-extension-manager.png" width="777" /></p>
|
|
<h3>Quiet Mode</h3>
|
|
<p>Both installation and uninstallation can be performed in quiet mode by using <strong>/quiet</strong> parameter. This will suppress
|
|
user interface of the installer, which is handy when you want to automate
|
|
Toolbox control integration with your custom installer.</p>
|
|
<h2><a name="net-versions">10. Supporting Multiple Version of .NET Framework</a></h2>
|
|
<p>Since .NET Framework is backward-compatible, building a component on lowest
|
|
possible framework ensures compatibility with higher versions as well.</p>
|
|
<p>I heard from several users that the component may not be displayed in Toolbox
|
|
although it seems that the Toolbox respects the .NET compatibility and display
|
|
.NET 2.0 component even when working in .NET 4.0 (Client Profile) project.</p>
|
|
<p>There is also a scenario where you want to support additional features from
|
|
higher version of .NET (for example, drawing text using GDI+ in .NET 2.0 and
|
|
drawing text using WPF in .NET 3.5 and higher). You may also want to add
|
|
extensive Windows Forms Designer support, which is not available in Client
|
|
Profile framework.</p>
|
|
<p>The solution to this is to build several DLLs, each with different features
|
|
and possibly different target frameworks. Then integrate all the assemblies.</p>
|
|
<p>This does not pose a problem when <strong>DTE</strong> approach is used,
|
|
alhtough it is better to give each version of the component unique name or place
|
|
them in separate tabs (e.g. "Component Owl WinForms - .NET 2.0").</p>
|
|
<p>When <strong>TCI</strong> approach is used, each version of the assembly
|
|
requires different public key token, because they have to reside in GAC
|
|
side-by-side. Furthermore, they need a separate registry key based on the public
|
|
key token.</p>
|
|
<p>The <strong>VSI</strong> and <strong>VSIX</strong> approaches require
|
|
renaming the component or customizing Toolbox tab in the
|
|
ProvideToolboxControlAttribute (see part <em>Toolbox Control Integration using
|
|
VSIX Packages</em> for more information).</p>
|
|
<p>The <strong>VSPackage</strong> approach allows you to place all the versions
|
|
in Visual Studio Toolbox under their respective tabs.</p>
|
|
<p>When <strong>manual approach</strong> is used, you can of course add each
|
|
version of the assembly separately and also create separate tabs in the Toolbox.</p>
|
|
|
|
<h2><a name="source">11. Sample Source Code</a></h2>
|
|
|
|
<p>The attached sample source is a Visual Studio 2010 Solution containing
|
|
implementations of all the presented approaches. The binaries are contained
|
|
under "bin\Release" subfolders and batch files (.CMD extension) are provided
|
|
where appropriate.</p>
|
|
|
|
<p align="center">
|
|
<a href="../toolbox-integration.zip">Download sample source code (212 KB)</a>
|
|
</p>
|
|
|
|
<p>You can find the following folders in the archive:</p>
|
|
<p><strong>DteToolboxInstaller</strong> - A command-line application for
|
|
installing/uninstalling assemblies in VS Toolbox using Visual Studio Automation
|
|
Object Model (DTE). Custom tab name and VS version can be specified. The tool
|
|
can be used in real-world application.</p>
|
|
<p><strong>SampleControl</strong> - Windows Forms control for testing the
|
|
integration.</p>
|
|
<p><strong>SampleVsixPackage</strong> - VSIX package project (basically a
|
|
VSPackage that is further packaged with the sample control), the resulting
|
|
package can be installed by VSIX Installer that comes with Visual Studio.</p>
|
|
<p><strong>SampleVsPackage</strong> - VSPackage that is able to install all
|
|
control assemblies located in its own folder. Contains batch files for package
|
|
registration/unregistration.</p>
|
|
<p><strong>SignVsix</strong> - A command-line application for signing VSIX
|
|
packages. Sample batch file is provided. Valid PFX certificate need to be
|
|
provided by the user.</p>
|
|
<p><strong>TciToolboxInstaller</strong> - A command-line application for
|
|
installing/uninstalling assemblies in VS Toolbox using Toolbox Control Installer
|
|
package (but does not depend on it). Custom tab name and VS version can be
|
|
specified. The tool can be used in real-world application.</p>
|
|
<p><strong>VSI</strong> - Basic setting for creating VSI package and a sample
|
|
VSI package created from the files. Batch file for signing the VSI package is
|
|
provided.</p>
|
|
<p> </p>
|
|
|
|
<p align="center">
|
|
<a href="../toolbox-integration.zip">Download sample source code (212 KB)</a>
|
|
</p>
|
|
|
|
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.Component Owl WinForms - .NET 2.0
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="right">
|
|
|
|
<div class="dextronet-feeds">
|
|
<ul class="links">
|
|
<li><a href="../feeds.rss" class="rss">Subscribe to our RSS</a></li>
|
|
<li><a href="http://twitter.com/ComponentOwl" class="twitter">Follow us on twitter</a></li>
|
|
<li><a href="https://www.facebook.com/ComponentOwl" class="facebook">Follow us on facebook</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="sidebar">
|
|
<h4>Better ListView</h4>
|
|
<a href="http://assets.componentowl.com/screenshots/15/blv-overview_original_1326499754.png?1326474554" class="screenshot" title="Better ListView control"><img alt="Better ListView" src="http://assets.componentowl.com/screenshots/15/blv-overview_thumb_1326499754.png?1326474554" /></a>
|
|
<div class="buttonz">
|
|
<a href="../betterlistview.exe" class="standard-download image-link" onclick="download_email('better-listview');">Free Download</a>
|
|
</div>
|
|
<div class="text">
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div id="screenshot-buttons" style="display: none">
|
|
<div class="buttons">
|
|
<a href="../betterlistview.exe" class="small-download image-link" onclick="download_email('better-listview');">Free Download</a>
|
|
<a href="../pricing-licensing/better-listview.html" class="small-buy image-link">See Pricing & Licensing</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="d-footer">
|
|
<div class="d-placing">
|
|
|
|
<div class="left">
|
|
<div class="latest-posts">
|
|
<h3 class="latest_from_blog"><a href="../blog.html">Latest From Our Blog</a></h3>
|
|
|
|
<h4><a href="../blog/index.html%3Fp=927.html">Activation issues and how to solve them</a></h4>
|
|
<div class="post-info">Wednesday, 01 March 2017</div>
|
|
|
|
<h4><a href="../blog/index.html%3Fp=921.html">The Three Main Advantages Better ListView has Over the Classic .NET Framework</a></h4>
|
|
<div class="post-info">Thursday, 09 February 2017</div>
|
|
|
|
<h4><a href="../blog/index.html%3Fp=914.html">BLV and Internet Explorer</a></h4>
|
|
<div class="post-info">Sunday, 13 November 2016</div>
|
|
|
|
<h4><a href="../blog/index.html%3Fp=906.html">Centering Images in Better ListView Sub-items</a></h4>
|
|
<div class="post-info">Wednesday, 06 August 2014</div>
|
|
|
|
<h4><a href="../blog/index.html%3Fp=901.html">Sub-item Check Boxes in Better ListView</a></h4>
|
|
<div class="post-info">Sunday, 06 July 2014</div>
|
|
|
|
</div>
|
|
<div class="other-posts"><a href="../blog.html">See more posts »</a></div>
|
|
</div>
|
|
|
|
<div class="right">
|
|
<div class="news">
|
|
<ul class="links">
|
|
<li><a href="../feeds.rss" class="rss">Subscribe to our RSS</a></li>
|
|
<li><a href="http://twitter.com/ComponentOwl" class="twitter">Follow us on twitter</a></li>
|
|
</ul>
|
|
|
|
<div class="news-item ">
|
|
<div class="date">27<span>May</span></div>
|
|
<div class="message">
|
|
|
|
<h4>Better ListView Express 3.15 released!</h4>
|
|
<p>
|
|
|
|
<a href="../betterlistviewexpress.exe" onclick="download_email('better-listview-express');">Download latest release</a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="news-item ">
|
|
<div class="date">27<span>May</span></div>
|
|
<div class="message">
|
|
|
|
<h4>Better ListView 3.15 released!</h4>
|
|
<p>
|
|
|
|
<a href="../betterlistview.exe" onclick="download_email('better-listview');">Download latest release</a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="news-item ">
|
|
<div class="date">27<span>May</span></div>
|
|
<div class="message">
|
|
|
|
<h4>Better SplitButton 3.15 released!</h4>
|
|
<p>
|
|
|
|
<a href="../bettersplitbutton.exe" onclick="download_email('better-splitbutton');">Download latest release</a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="news-item ">
|
|
<div class="date">27<span>May</span></div>
|
|
<div class="message">
|
|
|
|
<h4>Better Thumbnail Browser 3.15 released!</h4>
|
|
<p>
|
|
|
|
<a href="../betterthumbnailbrowser.exe" onclick="download_email('better-thumbnail-browser');">Download latest release</a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="news-item last-item">
|
|
<div class="date">08<span>Apr</span></div>
|
|
<div class="message">
|
|
|
|
<h4>Better ListView Express 3.14.0 released!</h4>
|
|
<p>
|
|
|
|
<a href="../better-listview-express/releases%3Fsince=3.14.0.html">See what's new</a>
|
|
or
|
|
|
|
<a href="../betterlistviewexpress.exe" onclick="download_email('better-listview-express');">Download latest release</a>
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="d-placing">
|
|
<hr />
|
|
<div class="copy"><div class="social"><a href="../support.html" class="feedback">Contact Us (Feedback)</a> <span>|</span> <a href="../feeds.rss" class="rss">RSS</a> <span>|</span> <a href="http://twitter.com/ComponentOwl" class="twitter">Twitter</a> <span>|</span> <a href="../sitemap.html" class="sitemap">Sitemap</a> <span>|</span> Our <a href="../index.html" class="stdl">task management software</a> that uses Better ListView</div>
|
|
Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read our <a href="../eula.html">EULA</a>, <a href="../disclaimer.html">Disclaimer</a> and <a href="../privacy-policy.html">Privacy Policy</a>.<br /></div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script src="../javascripts/app_packaged.js%3F1455269826" type="text/javascript"></script>
|
|
<script type="text/javascript">
|
|
|
|
var _gaq = _gaq || [];
|
|
_gaq.push(['_setAccount', 'UA-16362539-4']);
|
|
_gaq.push(['_trackPageview']);
|
|
|
|
(function() {
|
|
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
|
})();
|
|
|
|
</script>
|
|
<script src="http://load.sumome.com/" data-sumo-site-id="854b5e00f297990012cc230023375a00787c0000216621002775a800d79ad500" async="async"></script>
|
|
|
|
<!-- Place this tag after the last plusone tag -->
|
|
<script type="text/javascript">
|
|
(function() {
|
|
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
|
|
po.src = 'https://apis.google.com/js/plusone.js';
|
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
|
|
})();
|
|
</script>
|
|
|
|
</body>
|
|
</html> |