diff --git a/public/assets/comics/1/0000-angry_web_1312217558.png b/public/assets/comics/1/0000-angry_web_1312217558.png
new file mode 100644
index 0000000..204b98c
Binary files /dev/null and b/public/assets/comics/1/0000-angry_web_1312217558.png differ
diff --git a/public/assets/comics/10/0002-owl-dimensionality-web_web_1312882080.png b/public/assets/comics/10/0002-owl-dimensionality-web_web_1312882080.png
new file mode 100644
index 0000000..a397a4c
Binary files /dev/null and b/public/assets/comics/10/0002-owl-dimensionality-web_web_1312882080.png differ
diff --git a/public/assets/comics/11/0003-qa-black-magic_web_web_1312973269.png b/public/assets/comics/11/0003-qa-black-magic_web_web_1312973269.png
new file mode 100644
index 0000000..45d72fc
Binary files /dev/null and b/public/assets/comics/11/0003-qa-black-magic_web_web_1312973269.png differ
diff --git a/public/assets/comics/12/0004-dark-intellisense_web_web_1313141785.png b/public/assets/comics/12/0004-dark-intellisense_web_web_1313141785.png
new file mode 100644
index 0000000..07e85ed
Binary files /dev/null and b/public/assets/comics/12/0004-dark-intellisense_web_web_1313141785.png differ
diff --git a/public/assets/comics/13/0005-who-takes-the-credit_web_web_1313244880.png b/public/assets/comics/13/0005-who-takes-the-credit_web_web_1313244880.png
new file mode 100644
index 0000000..c2f917a
Binary files /dev/null and b/public/assets/comics/13/0005-who-takes-the-credit_web_web_1313244880.png differ
diff --git a/public/assets/comics/14/0006-ergonomic-chairs_web_web_1313244999.png b/public/assets/comics/14/0006-ergonomic-chairs_web_web_1313244999.png
new file mode 100644
index 0000000..1f72ee8
Binary files /dev/null and b/public/assets/comics/14/0006-ergonomic-chairs_web_web_1313244999.png differ
diff --git a/public/assets/comics/15/0007-the-meaningful-deadline_web_web_1313685127.png b/public/assets/comics/15/0007-the-meaningful-deadline_web_web_1313685127.png
new file mode 100644
index 0000000..da5abbd
Binary files /dev/null and b/public/assets/comics/15/0007-the-meaningful-deadline_web_web_1313685127.png differ
diff --git a/public/assets/comics/16/0008-green-productivity_web_web_1314037931.png b/public/assets/comics/16/0008-green-productivity_web_web_1314037931.png
new file mode 100644
index 0000000..4c30551
Binary files /dev/null and b/public/assets/comics/16/0008-green-productivity_web_web_1314037931.png differ
diff --git a/public/assets/comics/17/0009-from-scratch_web_web_1314809417.png b/public/assets/comics/17/0009-from-scratch_web_web_1314809417.png
new file mode 100644
index 0000000..f2647a1
Binary files /dev/null and b/public/assets/comics/17/0009-from-scratch_web_web_1314809417.png differ
diff --git a/public/assets/comics/18/0010-a-reward_web_web_1316015834.png b/public/assets/comics/18/0010-a-reward_web_web_1316015834.png
new file mode 100644
index 0000000..7bdd5c3
Binary files /dev/null and b/public/assets/comics/18/0010-a-reward_web_web_1316015834.png differ
diff --git a/public/assets/comics/19/0011-hard-discipline_web_web_1318625423.png b/public/assets/comics/19/0011-hard-discipline_web_web_1318625423.png
new file mode 100644
index 0000000..a56966a
Binary files /dev/null and b/public/assets/comics/19/0011-hard-discipline_web_web_1318625423.png differ
diff --git a/public/assets/comics/2/01-boss_and_the_worker-out_web_1312287061.png b/public/assets/comics/2/01-boss_and_the_worker-out_web_1312287061.png
new file mode 100644
index 0000000..f439717
Binary files /dev/null and b/public/assets/comics/2/01-boss_and_the_worker-out_web_1312287061.png differ
diff --git a/public/assets/comics/20/0012-breaking-the-nda-web_web_1321141101.png b/public/assets/comics/20/0012-breaking-the-nda-web_web_1321141101.png
new file mode 100644
index 0000000..013bc92
Binary files /dev/null and b/public/assets/comics/20/0012-breaking-the-nda-web_web_1321141101.png differ
diff --git a/public/assets/comics/21/0013-thorough-nda-web_web_1321359683.png b/public/assets/comics/21/0013-thorough-nda-web_web_1321359683.png
new file mode 100644
index 0000000..712c9a1
Binary files /dev/null and b/public/assets/comics/21/0013-thorough-nda-web_web_1321359683.png differ
diff --git a/public/assets/comics/22/0014-santa-courier-web_web_1322411181.png b/public/assets/comics/22/0014-santa-courier-web_web_1322411181.png
new file mode 100644
index 0000000..becb228
Binary files /dev/null and b/public/assets/comics/22/0014-santa-courier-web_web_1322411181.png differ
diff --git a/public/assets/comics/23/0015-write-it-a-thousand-times-web_web_1322855667.png b/public/assets/comics/23/0015-write-it-a-thousand-times-web_web_1322855667.png
new file mode 100644
index 0000000..6db71fd
Binary files /dev/null and b/public/assets/comics/23/0015-write-it-a-thousand-times-web_web_1322855667.png differ
diff --git a/public/assets/comics/24/0016-touch-the-tiles-web_web_1323309221.png b/public/assets/comics/24/0016-touch-the-tiles-web_web_1323309221.png
new file mode 100644
index 0000000..3f792ef
Binary files /dev/null and b/public/assets/comics/24/0016-touch-the-tiles-web_web_1323309221.png differ
diff --git a/public/assets/comics/25/0017-lazy-evaluation-web_web_1323736761.png b/public/assets/comics/25/0017-lazy-evaluation-web_web_1323736761.png
new file mode 100644
index 0000000..6692947
Binary files /dev/null and b/public/assets/comics/25/0017-lazy-evaluation-web_web_1323736761.png differ
diff --git a/public/assets/comics/26/0018-replacement-with-a-script-web_web_1324658954.png b/public/assets/comics/26/0018-replacement-with-a-script-web_web_1324658954.png
new file mode 100644
index 0000000..bbcc5aa
Binary files /dev/null and b/public/assets/comics/26/0018-replacement-with-a-script-web_web_1324658954.png differ
diff --git a/public/assets/comics/27/0019-human-resources-web_web_1325082644.png b/public/assets/comics/27/0019-human-resources-web_web_1325082644.png
new file mode 100644
index 0000000..43ec768
Binary files /dev/null and b/public/assets/comics/27/0019-human-resources-web_web_1325082644.png differ
diff --git a/public/assets/comics/28/0020-nonstop-dev-team_web_web_1330007563.png b/public/assets/comics/28/0020-nonstop-dev-team_web_web_1330007563.png
new file mode 100644
index 0000000..da2e2d8
Binary files /dev/null and b/public/assets/comics/28/0020-nonstop-dev-team_web_web_1330007563.png differ
diff --git a/public/assets/comics/29/0021-lsd_web_web_1335527057.png b/public/assets/comics/29/0021-lsd_web_web_1335527057.png
new file mode 100644
index 0000000..83d222f
Binary files /dev/null and b/public/assets/comics/29/0021-lsd_web_web_1335527057.png differ
diff --git a/public/assets/comics/30/0022-badge-of-shame-web_web_1336135809.png b/public/assets/comics/30/0022-badge-of-shame-web_web_1336135809.png
new file mode 100644
index 0000000..e1f6ba8
Binary files /dev/null and b/public/assets/comics/30/0022-badge-of-shame-web_web_1336135809.png differ
diff --git a/public/assets/comics/31/0023-bloody-cartridge-web_web_1336498077.png b/public/assets/comics/31/0023-bloody-cartridge-web_web_1336498077.png
new file mode 100644
index 0000000..46e8fd2
Binary files /dev/null and b/public/assets/comics/31/0023-bloody-cartridge-web_web_1336498077.png differ
diff --git a/public/assets/comics/32/0024-from-the-ground-up-web_web_1336955366.png b/public/assets/comics/32/0024-from-the-ground-up-web_web_1336955366.png
new file mode 100644
index 0000000..4bdb5fb
Binary files /dev/null and b/public/assets/comics/32/0024-from-the-ground-up-web_web_1336955366.png differ
diff --git a/public/assets/comics/33/0025-boxed-office-web_web_1337198604.png b/public/assets/comics/33/0025-boxed-office-web_web_1337198604.png
new file mode 100644
index 0000000..beda19c
Binary files /dev/null and b/public/assets/comics/33/0025-boxed-office-web_web_1337198604.png differ
diff --git a/public/assets/comics/34/0026-pet-scanner-web_web_1337979080.png b/public/assets/comics/34/0026-pet-scanner-web_web_1337979080.png
new file mode 100644
index 0000000..6bd4adc
Binary files /dev/null and b/public/assets/comics/34/0026-pet-scanner-web_web_1337979080.png differ
diff --git a/public/assets/comics/35/0027-skyscraper-web_web_1338077520.png b/public/assets/comics/35/0027-skyscraper-web_web_1338077520.png
new file mode 100644
index 0000000..5483427
Binary files /dev/null and b/public/assets/comics/35/0027-skyscraper-web_web_1338077520.png differ
diff --git a/public/assets/comics/36/0028-coin-machine-web_web_1338424277.png b/public/assets/comics/36/0028-coin-machine-web_web_1338424277.png
new file mode 100644
index 0000000..0171ced
Binary files /dev/null and b/public/assets/comics/36/0028-coin-machine-web_web_1338424277.png differ
diff --git a/public/assets/comics/37/0029-amphetamine-coffee-web_web_1338592639.png b/public/assets/comics/37/0029-amphetamine-coffee-web_web_1338592639.png
new file mode 100644
index 0000000..5564e09
Binary files /dev/null and b/public/assets/comics/37/0029-amphetamine-coffee-web_web_1338592639.png differ
diff --git a/public/assets/comics/38/0030-office-animals-web_web_1339281061.png b/public/assets/comics/38/0030-office-animals-web_web_1339281061.png
new file mode 100644
index 0000000..afffacd
Binary files /dev/null and b/public/assets/comics/38/0030-office-animals-web_web_1339281061.png differ
diff --git a/public/assets/comics/39/0031-project-triangle-web_web_1340062832.png b/public/assets/comics/39/0031-project-triangle-web_web_1340062832.png
new file mode 100644
index 0000000..1e5bb0d
Binary files /dev/null and b/public/assets/comics/39/0031-project-triangle-web_web_1340062832.png differ
diff --git a/public/assets/comics/4/03-whole-food-honey-out_web_1312377904.png b/public/assets/comics/4/03-whole-food-honey-out_web_1312377904.png
new file mode 100644
index 0000000..50b166a
Binary files /dev/null and b/public/assets/comics/4/03-whole-food-honey-out_web_1312377904.png differ
diff --git a/public/assets/comics/40/0032-investment-cloud-web_web_1340911880.png b/public/assets/comics/40/0032-investment-cloud-web_web_1340911880.png
new file mode 100644
index 0000000..83a8c96
Binary files /dev/null and b/public/assets/comics/40/0032-investment-cloud-web_web_1340911880.png differ
diff --git a/public/assets/comics/41/0033-the-smoker-web_web_1346260357.png b/public/assets/comics/41/0033-the-smoker-web_web_1346260357.png
new file mode 100644
index 0000000..359e307
Binary files /dev/null and b/public/assets/comics/41/0033-the-smoker-web_web_1346260357.png differ
diff --git a/public/assets/comics/42/0034-the-assassin-web_web_1349211995.png b/public/assets/comics/42/0034-the-assassin-web_web_1349211995.png
new file mode 100644
index 0000000..c92c505
Binary files /dev/null and b/public/assets/comics/42/0034-the-assassin-web_web_1349211995.png differ
diff --git a/public/assets/comics/43/0035-extra-dimension-web_web_1352715455.png b/public/assets/comics/43/0035-extra-dimension-web_web_1352715455.png
new file mode 100644
index 0000000..f57e613
Binary files /dev/null and b/public/assets/comics/43/0035-extra-dimension-web_web_1352715455.png differ
diff --git a/public/assets/comics/44/0036-budget-cuts-web_web_1354427969.png b/public/assets/comics/44/0036-budget-cuts-web_web_1354427969.png
new file mode 100644
index 0000000..20cef04
Binary files /dev/null and b/public/assets/comics/44/0036-budget-cuts-web_web_1354427969.png differ
diff --git a/public/assets/comics/5/0007-bugs_web_1312448241.png b/public/assets/comics/5/0007-bugs_web_1312448241.png
new file mode 100644
index 0000000..5ccf94f
Binary files /dev/null and b/public/assets/comics/5/0007-bugs_web_1312448241.png differ
diff --git a/public/assets/comics/6/0008-food-chain_web_1312543561.png b/public/assets/comics/6/0008-food-chain_web_1312543561.png
new file mode 100644
index 0000000..3f61ac5
Binary files /dev/null and b/public/assets/comics/6/0008-food-chain_web_1312543561.png differ
diff --git a/public/assets/comics/7/0009-mono_web_1312634072.png b/public/assets/comics/7/0009-mono_web_1312634072.png
new file mode 100644
index 0000000..ec274c6
Binary files /dev/null and b/public/assets/comics/7/0009-mono_web_1312634072.png differ
diff --git a/public/assets/comics/8/0011-a-toilet-paper_web_1312711686.png b/public/assets/comics/8/0011-a-toilet-paper_web_1312711686.png
new file mode 100644
index 0000000..2416e3b
Binary files /dev/null and b/public/assets/comics/8/0011-a-toilet-paper_web_1312711686.png differ
diff --git a/public/assets/comics/9/0001-a-diagram-web_web_1312798348.png b/public/assets/comics/9/0001-a-diagram-web_web_1312798348.png
new file mode 100644
index 0000000..3a47fd5
Binary files /dev/null and b/public/assets/comics/9/0001-a-diagram-web_web_1312798348.png differ
diff --git a/public/assets/icons/better-listview-32-1355160256.png b/public/assets/icons/better-listview-32-1355160256.png
new file mode 100644
index 0000000..cf26e61
Binary files /dev/null and b/public/assets/icons/better-listview-32-1355160256.png differ
diff --git a/public/assets/icons/better-listview-express-32-1355160327.png b/public/assets/icons/better-listview-express-32-1355160327.png
new file mode 100644
index 0000000..cf26e61
Binary files /dev/null and b/public/assets/icons/better-listview-express-32-1355160327.png differ
diff --git a/public/assets/icons/better-splitbutton-32-1355160307.png b/public/assets/icons/better-splitbutton-32-1355160307.png
new file mode 100644
index 0000000..8d10eaa
Binary files /dev/null and b/public/assets/icons/better-splitbutton-32-1355160307.png differ
diff --git a/public/assets/icons/better-thumbnail-browser-32-1355160281.png b/public/assets/icons/better-thumbnail-browser-32-1355160281.png
new file mode 100644
index 0000000..5a7d83d
Binary files /dev/null and b/public/assets/icons/better-thumbnail-browser-32-1355160281.png differ
diff --git a/public/assets/images/10/Column Headers In LargeIcons View_original_1298622038.png b/public/assets/images/10/Column Headers In LargeIcons View_original_1298622038.png
new file mode 100644
index 0000000..be9bc3d
Binary files /dev/null and b/public/assets/images/10/Column Headers In LargeIcons View_original_1298622038.png differ
diff --git a/public/assets/images/11/ListView Image Shadows and Image Borders_original_1298622678.png b/public/assets/images/11/ListView Image Shadows and Image Borders_original_1298622678.png
new file mode 100644
index 0000000..04c1d92
Binary files /dev/null and b/public/assets/images/11/ListView Image Shadows and Image Borders_original_1298622678.png differ
diff --git a/public/assets/images/12/Multi Column Sort in List View_original_1298623013.png b/public/assets/images/12/Multi Column Sort in List View_original_1298623013.png
new file mode 100644
index 0000000..d7ddc05
Binary files /dev/null and b/public/assets/images/12/Multi Column Sort in List View_original_1298623013.png differ
diff --git a/public/assets/images/13/Checkboxes In LargeIcons View_original_1298623385.png b/public/assets/images/13/Checkboxes In LargeIcons View_original_1298623385.png
new file mode 100644
index 0000000..23ac1d8
Binary files /dev/null and b/public/assets/images/13/Checkboxes In LargeIcons View_original_1298623385.png differ
diff --git a/public/assets/images/14/Three State Checkboxes in List View_original_1298624577.png b/public/assets/images/14/Three State Checkboxes in List View_original_1298624577.png
new file mode 100644
index 0000000..9b4aa8b
Binary files /dev/null and b/public/assets/images/14/Three State Checkboxes in List View_original_1298624577.png differ
diff --git a/public/assets/images/15/List View Tooltips Region And Owner Drawn Tooltips_original_1298632357.png b/public/assets/images/15/List View Tooltips Region And Owner Drawn Tooltips_original_1298632357.png
new file mode 100644
index 0000000..9b0bcfc
Binary files /dev/null and b/public/assets/images/15/List View Tooltips Region And Owner Drawn Tooltips_original_1298632357.png differ
diff --git a/public/assets/images/17/Column Header Context Menu in List View_original_1298721855.png b/public/assets/images/17/Column Header Context Menu in List View_original_1298721855.png
new file mode 100644
index 0000000..464a513
Binary files /dev/null and b/public/assets/images/17/Column Header Context Menu in List View_original_1298721855.png differ
diff --git a/public/assets/images/18/Show Text When List View is Empty_original_1298629916.png b/public/assets/images/18/Show Text When List View is Empty_original_1298629916.png
new file mode 100644
index 0000000..80f0347
Binary files /dev/null and b/public/assets/images/18/Show Text When List View is Empty_original_1298629916.png differ
diff --git a/public/assets/images/19/Custom Embedded Control in List View for Editing_original_1298630263.png b/public/assets/images/19/Custom Embedded Control in List View for Editing_original_1298630263.png
new file mode 100644
index 0000000..315c4f9
Binary files /dev/null and b/public/assets/images/19/Custom Embedded Control in List View for Editing_original_1298630263.png differ
diff --git a/public/assets/images/20/Custom Item Size in List View_original_1298630739.png b/public/assets/images/20/Custom Item Size in List View_original_1298630739.png
new file mode 100644
index 0000000..e8f2639
Binary files /dev/null and b/public/assets/images/20/Custom Item Size in List View_original_1298630739.png differ
diff --git a/public/assets/images/21/List View Item Reordering Mark Preview_original_1298631798.png b/public/assets/images/21/List View Item Reordering Mark Preview_original_1298631798.png
new file mode 100644
index 0000000..f9dafd7
Binary files /dev/null and b/public/assets/images/21/List View Item Reordering Mark Preview_original_1298631798.png differ
diff --git a/public/assets/images/22/List View Owner Drawing Background Gradient_original_1298633053.png b/public/assets/images/22/List View Owner Drawing Background Gradient_original_1298633053.png
new file mode 100644
index 0000000..9a8bd94
Binary files /dev/null and b/public/assets/images/22/List View Owner Drawing Background Gradient_original_1298633053.png differ
diff --git a/public/assets/images/23/show-or-hide-checkboxes-for-specific-listview-items_original_1299748307.png b/public/assets/images/23/show-or-hide-checkboxes-for-specific-listview-items_original_1299748307.png
new file mode 100644
index 0000000..714585a
Binary files /dev/null and b/public/assets/images/23/show-or-hide-checkboxes-for-specific-listview-items_original_1299748307.png differ
diff --git a/public/assets/images/25/focus-list-view-sub-items_original_1313674098.png b/public/assets/images/25/focus-list-view-sub-items_original_1313674098.png
new file mode 100644
index 0000000..2ec7fff
Binary files /dev/null and b/public/assets/images/25/focus-list-view-sub-items_original_1313674098.png differ
diff --git a/public/assets/images/26/Advanced-Hit-Test_original_1326105831.png b/public/assets/images/26/Advanced-Hit-Test_original_1326105831.png
new file mode 100644
index 0000000..0e7ad68
Binary files /dev/null and b/public/assets/images/26/Advanced-Hit-Test_original_1326105831.png differ
diff --git a/public/assets/images/27/Background-Images_original_1326106027.png b/public/assets/images/27/Background-Images_original_1326106027.png
new file mode 100644
index 0000000..1fdb177
Binary files /dev/null and b/public/assets/images/27/Background-Images_original_1326106027.png differ
diff --git a/public/assets/images/29/Background-Images_original_1326106990.png b/public/assets/images/29/Background-Images_original_1326106990.png
new file mode 100644
index 0000000..6a4a2ca
Binary files /dev/null and b/public/assets/images/29/Background-Images_original_1326106990.png differ
diff --git a/public/assets/images/31/Column-Images-Sub-Item-Images-Groups-Images_original_1326107040.png b/public/assets/images/31/Column-Images-Sub-Item-Images-Groups-Images_original_1326107040.png
new file mode 100644
index 0000000..bff2ffd
Binary files /dev/null and b/public/assets/images/31/Column-Images-Sub-Item-Images-Groups-Images_original_1326107040.png differ
diff --git a/public/assets/images/32/Custom-Embedded-Controls-For-Label-Edit_original_1326107064.png b/public/assets/images/32/Custom-Embedded-Controls-For-Label-Edit_original_1326107064.png
new file mode 100644
index 0000000..78b43e6
Binary files /dev/null and b/public/assets/images/32/Custom-Embedded-Controls-For-Label-Edit_original_1326107064.png differ
diff --git a/public/assets/images/33/Custom-Sub-Item-Label-Edit_original_1326107089.png b/public/assets/images/33/Custom-Sub-Item-Label-Edit_original_1326107089.png
new file mode 100644
index 0000000..c564275
Binary files /dev/null and b/public/assets/images/33/Custom-Sub-Item-Label-Edit_original_1326107089.png differ
diff --git a/public/assets/images/34/Focusable-Advanced-Groups-With-Image-Support_original_1326107120.png b/public/assets/images/34/Focusable-Advanced-Groups-With-Image-Support_original_1326107120.png
new file mode 100644
index 0000000..0131a64
Binary files /dev/null and b/public/assets/images/34/Focusable-Advanced-Groups-With-Image-Support_original_1326107120.png differ
diff --git a/public/assets/images/36/product-image_original_1328613483.png b/public/assets/images/36/product-image_original_1328613483.png
new file mode 100644
index 0000000..b1ed663
Binary files /dev/null and b/public/assets/images/36/product-image_original_1328613483.png differ
diff --git a/public/assets/images/7/Overview Collage_original_1367470843.png b/public/assets/images/7/Overview Collage_original_1367470843.png
new file mode 100644
index 0000000..9e0d06f
Binary files /dev/null and b/public/assets/images/7/Overview Collage_original_1367470843.png differ
diff --git a/public/assets/images/8/Column Header Images_original_1298620501.png b/public/assets/images/8/Column Header Images_original_1298620501.png
new file mode 100644
index 0000000..609f503
Binary files /dev/null and b/public/assets/images/8/Column Header Images_original_1298620501.png differ
diff --git a/public/assets/images/9/Column Header Reordering With Insertion Mark_original_1298621331.png b/public/assets/images/9/Column Header Reordering With Insertion Mark_original_1298621331.png
new file mode 100644
index 0000000..64cc472
Binary files /dev/null and b/public/assets/images/9/Column Header Reordering With Insertion Mark_original_1298621331.png differ
diff --git a/public/assets/screenshots/15/blv-overview_original_1326499754.png b/public/assets/screenshots/15/blv-overview_original_1326499754.png
new file mode 100644
index 0000000..e67a355
Binary files /dev/null and b/public/assets/screenshots/15/blv-overview_original_1326499754.png differ
diff --git a/public/assets/screenshots/15/blv-overview_thumb_1326499754.png b/public/assets/screenshots/15/blv-overview_thumb_1326499754.png
new file mode 100644
index 0000000..0ad076e
Binary files /dev/null and b/public/assets/screenshots/15/blv-overview_thumb_1326499754.png differ
diff --git a/public/assets/screenshots/16/thumbnails_original_1312133021.png b/public/assets/screenshots/16/thumbnails_original_1312133021.png
new file mode 100644
index 0000000..73f2398
Binary files /dev/null and b/public/assets/screenshots/16/thumbnails_original_1312133021.png differ
diff --git a/public/assets/screenshots/16/thumbnails_thumb_1312133021.png b/public/assets/screenshots/16/thumbnails_thumb_1312133021.png
new file mode 100644
index 0000000..f313523
Binary files /dev/null and b/public/assets/screenshots/16/thumbnails_thumb_1312133021.png differ
diff --git a/public/assets/screenshots/18/betterlistview-tree-hierarchy_original_1313676477.png b/public/assets/screenshots/18/betterlistview-tree-hierarchy_original_1313676477.png
new file mode 100644
index 0000000..2e30e56
Binary files /dev/null and b/public/assets/screenshots/18/betterlistview-tree-hierarchy_original_1313676477.png differ
diff --git a/public/assets/screenshots/18/betterlistview-tree-hierarchy_thumb_1313676477.png b/public/assets/screenshots/18/betterlistview-tree-hierarchy_thumb_1313676477.png
new file mode 100644
index 0000000..0065552
Binary files /dev/null and b/public/assets/screenshots/18/betterlistview-tree-hierarchy_thumb_1313676477.png differ
diff --git a/public/assets/screenshots/21/multi-line-items_original_1312133213.png b/public/assets/screenshots/21/multi-line-items_original_1312133213.png
new file mode 100644
index 0000000..35893f5
Binary files /dev/null and b/public/assets/screenshots/21/multi-line-items_original_1312133213.png differ
diff --git a/public/assets/screenshots/21/multi-line-items_thumb_1312133213.png b/public/assets/screenshots/21/multi-line-items_thumb_1312133213.png
new file mode 100644
index 0000000..aec5229
Binary files /dev/null and b/public/assets/screenshots/21/multi-line-items_thumb_1312133213.png differ
diff --git a/public/assets/screenshots/34/better-splitbutton-overview_original_1328267692.png b/public/assets/screenshots/34/better-splitbutton-overview_original_1328267692.png
new file mode 100644
index 0000000..2ff6a93
Binary files /dev/null and b/public/assets/screenshots/34/better-splitbutton-overview_original_1328267692.png differ
diff --git a/public/assets/screenshots/34/better-splitbutton-overview_thumb_1328267692.png b/public/assets/screenshots/34/better-splitbutton-overview_thumb_1328267692.png
new file mode 100644
index 0000000..d825313
Binary files /dev/null and b/public/assets/screenshots/34/better-splitbutton-overview_thumb_1328267692.png differ
diff --git a/public/assets/screenshots/35/always-drop-down_original_1328267712.png b/public/assets/screenshots/35/always-drop-down_original_1328267712.png
new file mode 100644
index 0000000..bb94151
Binary files /dev/null and b/public/assets/screenshots/35/always-drop-down_original_1328267712.png differ
diff --git a/public/assets/screenshots/35/always-drop-down_thumb_1328267712.png b/public/assets/screenshots/35/always-drop-down_thumb_1328267712.png
new file mode 100644
index 0000000..ba05d6c
Binary files /dev/null and b/public/assets/screenshots/35/always-drop-down_thumb_1328267712.png differ
diff --git a/public/assets/screenshots/36/flat-style_original_1328267962.png b/public/assets/screenshots/36/flat-style_original_1328267962.png
new file mode 100644
index 0000000..6624418
Binary files /dev/null and b/public/assets/screenshots/36/flat-style_original_1328267962.png differ
diff --git a/public/assets/screenshots/36/flat-style_thumb_1328267962.png b/public/assets/screenshots/36/flat-style_thumb_1328267962.png
new file mode 100644
index 0000000..125f846
Binary files /dev/null and b/public/assets/screenshots/36/flat-style_thumb_1328267962.png differ
diff --git a/public/assets/screenshots/37/image-list_original_1328268002.png b/public/assets/screenshots/37/image-list_original_1328268002.png
new file mode 100644
index 0000000..22763e6
Binary files /dev/null and b/public/assets/screenshots/37/image-list_original_1328268002.png differ
diff --git a/public/assets/screenshots/37/image-list_thumb_1328268002.png b/public/assets/screenshots/37/image-list_thumb_1328268002.png
new file mode 100644
index 0000000..f1063d9
Binary files /dev/null and b/public/assets/screenshots/37/image-list_thumb_1328268002.png differ
diff --git a/public/assets/screenshots/43/overview_original_1354296079.png b/public/assets/screenshots/43/overview_original_1354296079.png
new file mode 100644
index 0000000..034dd8f
Binary files /dev/null and b/public/assets/screenshots/43/overview_original_1354296079.png differ
diff --git a/public/assets/screenshots/43/overview_thumb_1354296079.png b/public/assets/screenshots/43/overview_thumb_1354296079.png
new file mode 100644
index 0000000..6c704c7
Binary files /dev/null and b/public/assets/screenshots/43/overview_thumb_1354296079.png differ
diff --git a/public/assets/screenshots/44/using-auto-populate_original_1354296146.png b/public/assets/screenshots/44/using-auto-populate_original_1354296146.png
new file mode 100644
index 0000000..cce7178
Binary files /dev/null and b/public/assets/screenshots/44/using-auto-populate_original_1354296146.png differ
diff --git a/public/assets/screenshots/44/using-auto-populate_thumb_1354296146.png b/public/assets/screenshots/44/using-auto-populate_thumb_1354296146.png
new file mode 100644
index 0000000..9080f7c
Binary files /dev/null and b/public/assets/screenshots/44/using-auto-populate_thumb_1354296146.png differ
diff --git a/public/assets/screenshots/45/using-sorting_original_1354296174.png b/public/assets/screenshots/45/using-sorting_original_1354296174.png
new file mode 100644
index 0000000..104c7fd
Binary files /dev/null and b/public/assets/screenshots/45/using-sorting_original_1354296174.png differ
diff --git a/public/assets/screenshots/45/using-sorting_thumb_1354296174.png b/public/assets/screenshots/45/using-sorting_thumb_1354296174.png
new file mode 100644
index 0000000..3e0f733
Binary files /dev/null and b/public/assets/screenshots/45/using-sorting_thumb_1354296174.png differ
diff --git a/public/assets/screenshots/46/layout-thumbnails-spacing_original_1354296209.jpg b/public/assets/screenshots/46/layout-thumbnails-spacing_original_1354296209.jpg
new file mode 100644
index 0000000..235ead8
Binary files /dev/null and b/public/assets/screenshots/46/layout-thumbnails-spacing_original_1354296209.jpg differ
diff --git a/public/assets/screenshots/46/layout-thumbnails-spacing_thumb_1354296209.jpg b/public/assets/screenshots/46/layout-thumbnails-spacing_thumb_1354296209.jpg
new file mode 100644
index 0000000..a2a4cc0
Binary files /dev/null and b/public/assets/screenshots/46/layout-thumbnails-spacing_thumb_1354296209.jpg differ
diff --git a/public/class-reference/better-listview/hxlinktable.htc.html b/public/class-reference/better-listview/hxlinktable.htc.html
index b716ec9..871bbfc 100644
--- a/public/class-reference/better-listview/hxlinktable.htc.html
+++ b/public/class-reference/better-listview/hxlinktable.htc.html
@@ -53,16 +53,16 @@ height="0" width="0" style="display:none;visibility:hidden">
-
-
-
-
-
The Most Complete Guide to Visual Studio Toolbox Control Integration
-
Libor
-Tinka, Lead Developer, ComponentOwl.com
-
-
-
Contents
-
1. Introduction
-2. Prerequisites
-3. Creating a Sample Control
-4. Manual Toolbox Integration
-5. Toolbox Integration using TCI
-6. Toolbox Integration using DTE
-7. Toolbox Integration using VSI Packages
-8. Toolbox Integration using VSPackages
-9. Toolbox Integration using VSIX Packages
-10. Supporting Multiple Version of .NET Framework
-11. Sample Source Code
-
-
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.
-
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.
-
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:
-
- - How to install control in Visual Studio Toolbox?
- - How to update the control?
- - How to uninstall/remove the control?
- - How to support multiple Visual Studio versions?
-
-
There are several options on how to integrate your controls with Visual
-Studio Toolbox:
-
- - Manual installation
- - Toolbox Control Installer (TCI)
- - Visual Studio Automation Object Model (DTE)
- - VSPackage
- - VSI package
- - VSIX package
-
-
Manual installation
-
The simplest way of adding control into Visual Studio Toolbox is from within
-the IDE.
-
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.
-
Advantages: zero effort
-Disadvantages: require experienced users, slows user
-producitivity, updating controls is not intuitive
-
Toolbox Control Installer (TCI)
-
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.
-
Advantages: simple and fast component installation, updating
-and removing
-Disadvantages: requires installation in GAC (not always
-wanted), VS 2005 supported with SDK only
-
Visual Studio Automation Object Model (DTE)
-
If you are not afraid of COM, you can try DTE (Development Tools Environment) approach.
-There is already a project on CodePlex called
-Visual Studio Toolbox Manager,
-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 DteToolboxInstaller, which
-is also a command-line application and does 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.
-
Advantages: does not require updating registry or GAC, full
-control over Toolbox
-Disadvantages: very slow, separate installation required for
-every version of Visual Studio
-
VSPackage
-
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.
-
Advantages: quick installation, appearance in About box and
-other extensibility features
-Disadvantages: cmplicated setup, each component requires its
-own package if shipped separately
-
VSI Package
-
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.
-
Advantages: simple creation, installer provided by Visual
-Studio, automated creation and signing requires several specific steps
-Disadvantages: no quiet mode (extra steps when custom installer
-is used), manual uninstallation
-
VSIX Package
-
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: "This extension does not contain a digital signature."
-Even better news: The VsixInstaller supports quiet mode!
-
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.
-
Advantages: installer provided by Visual Studio, quiet mode,
-fast installation
-Disadvantages: package project required, automated creation is
-complicated, no support for VS 2005 and 2008
-
Comparison of Approaches
-
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.
-
-
- | |
- 2005 |
- 2008 |
- 2010 |
- 2012 |
- 2013 |
- Speed |
- Install Automation |
- Uninstall automation |
-
-
- | Manual installation |
-  |
-  |
-  |
-  |
-  |
- depends on user |
-  |
-  |
-
-
- | TCI |
-  |
-  |
-  |
-  |
-  |
- fast |
-  |
- |
-
-
- | EnvDTE |
-  |
-  |
-  |
-  |
-  |
- slow |
-  |
- |
-
-
- | VSI |
-  |
-  |
-  |
-  |
-  |
- moderate |
-  |
- |
-
-
- | VSIX |
-  |
-  |
-  |
-  |
-  |
- moderate (faster than VSI) |
-  |
- |
-
-
- | VSPackage |
-  |
-  |
-  |
-  |
-  |
- fast |
-  |
- |
-
-
-
-
-
We will focus on integration with Visual Studio 2010, 2012 and 2013. Hence you will need:
-
- - Visual Studio 2010 (or 2012, 2013)
- - Visual Studio 2010 SDK (or 2012 SDK, 2013 SDK)
- - Microsoft Windows SDK
-
-
The VS SDK contains regpkg.exe tool and project templates discussed in VSIX
-and VSPackage approaches.
-
The Windows SDK contains gacutil.exe, guidgen.exe, signtool.exe and other
-useful tools.
-
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:
-
-
- | Release name |
- Version number |
-
-
- | Visual Studio 2005 |
- 8.0 |
-
-
- | Visual Studio 2008 |
- 9.0 |
-
-
- | Visual Studio 2010 |
- 10.0 |
-
-
- | Visual Studio 2012 |
- 11.0 |
-
-
- | Visual Studio 2013 |
- 12.0 |
-
-
-
-
We will start by creating simple WinForms control for integration in VS
-Toolbox.
-
You can start with File - New - Project... (Control+Shift+N) and select
-Windows Forms Controls Library template.
-
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 Control will
-suffice.
-
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
-unless you use some feature specific to 4.5.
-
If you have multiple controls in your assembly and don't want to use some of
-them in Toolbox, decorate them with ToolboxItem attribute with
-defaultType parameter set to false:
-
-[ToolboxItem(false)]
-public class InvisibleControl : UserControl
-{
- ...
-}
-
-
I have created a very simple control called SampleControl:
-

-
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).
-
Custom Transparent Icon for the Toolbox
-
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):
-

-
The icon file should have same name as the control class (i.e.
-SampleControl.BMP).
-
Finally, use ToolboxBitmapAttribute to link icon with the control class:
-
-[ToolboxBitmap(typeof(SampleControl), "Resources.SampleControl.bmp")]
-public partial class SampleControl : UserControl
-{
- ...
-}
-
-
Note that icon location matters, at least in C#. Since I have added
-the icon under custom folder named Resources, I need to reference
-Resources.SampleControl.bmp instead of just SampleControl.bmp.
-
Here is the resulting transparent icon in Toolbox:
-

-
Marking the Control as Toolbox Item
-
We can mark control as toolbox item by adding a ToolboxItemAttribute
-with defaultType parameter set to true:
-
-[ToolboxItem(true)]
-public partial class SampleControl : UserControl
-...
-
-
This decoration is optional since the controls within assembly are
-considered toolbox items by default. However, we can mark certain control
-classes with ToolboxItem(false) 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.
-
Signing the Assembly
-
The assembly containing controls (SampleControl.dll 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.
-
To give an assembly a strong name, open project properties and find
-Signing tab:
-

-
Check the "Sign the assembly" option and select "<New...>"
-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).
-
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.
-
-
Installing
-
To install component into Visual Studio Toolbox manually, open some form or
-control in designer, open the Toolbox window (Control+Alt+X), right-click on the
-Toolbox window and select "Choose Items...":
-

-
The "Choose Toolbox Items" dialog will show up:
-

-
You can browse for DLL file with your component by clicking the "Browse..."
-button.
-
This is the simplest way of putting component in the Toolbox without extra
-actions required.
-
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.
-
Making the Control Visible in "Choose Toolbox Items" Dialog Box
-
As you can see on the above picture, the SampleControl component is already
-displayed in the dialog box under ".NET Framework Components" tab.
-
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.
-
You can register your own assembly this way by creating a key in registry:
-
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\<your control name>
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\<your control name>
-
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):
-
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
-
In both cases, the default value for the key is a string with full path to
-the folder with your assembly.
-
You can specify Toolbox tab in which the component should show up by adding
-subkey named "Toolbox" with single string value "TabName" 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:
-
-
-
The control should also appear in "Choose Toolbox Items" dialog box if it
-is installed in Global Assembly Cache.
-
The control pops up in the Toolbox automatically in
-its own tab in Visual Studio 2012/2013.
-
Installing the Control in GAC
-
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).
-
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 true 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.
-
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.
-
You can work with GAC by using tool called gacutil.exe or
-from code. We will discuss both approaches.
-
The gacutil.exe is located in Microsoft Windows SDK directory. There are two
-such extecutables:
-
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
-
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.
-
You can install an assembly to GAC by calling:
-
gacutil.exe /i SampleControl.dll
-
To uninstall it, we refer to our assembly by its assembly name, not file
-name:
-
gacutil.exe /u SampleControl
-
Finally, you can check if the assembly is installed in GAC by listing any
-instances of the provided name:
-
gacutil.exe /l SampleControl
-
It is not wise, however, to use gacutil.exe from a custom
-installer as it is located in SDK that user might not have installed.
-Furthermore, the SDK license does not allow bundling gacutil.exe
-with your installer.
-
Some installers like Inno Setup or MSI allow installing in GAC anyway.
-
You can also work with GAC using
-System.EnterpriseServices.Internal.Publish class. The class have two
-methods: GacInstall and GacRemove. Both
-methods take just path to assembly file as a parameter, so for example:
-
(new Publish()).GacInstall(assemblyPath);
-
will install the specified assembly in GAC.
-
Updating
-
Updating the control depends on how it is installed and referenced.
-
If you have added component in the Toolbox manually via "Choose Toolbox Items"
-dialog box and "Browse..." button, i.e. as a file reference, 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
-true in reference properties window; the default is
-false in this case). Simply replacing the DLL with the control by a newer
-file will suffice. If the user have specified "Specific Version" to true,
-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.
-
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 true by default:
-

-
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.
-
If you remove all versions of the component from GAC (e.g. using
-gacutil.exe) and then install just the newest one, the build will break
-unless the user changed "Specific Version" property to false.
-
Removing
-
Removing the manually installed control consists of just reverting all the
-steps done during the installation.
-
In case of file references, deleting the file is sufficient.
-
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 gacutil.exe).
-
Resetting Toolbox and Clearing the Toolbox Cache
-
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.
-
To do that, right-click on the Toolbox window and select "Reset
-Toolbox". Visual Studio will go through all the installed packages and reloads
-components into the Toolbox.
-
If this won't help, you can perform hard reset of the Toolbox. Exit
-Visual Studio and delete all .TBD files in the following folder:
-
\Users\<user>\AppData\Local\Microsoft\VisualStudio\10.0\
-
It should be up to four files:
-

-
Once removed, start Visual Studio again. After showing the Toolbox, all items
-should load instead of loading only the cached versions.
-
-
Installing
-
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.
-
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:
-
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
-
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).
-
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.
-
The installation consists of putting the control in GAC (see previous
-section for more information) and creating registry keys.
-
Suppose we have the SampleControl installed in GAC:
-

-
We will make reference to this assembly from registry by creating the
-following key:
-
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
-
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".
-
Installing in Visual Studio 2012 and 2013
-
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.:
-
HKCU\Software\Microsoft\VisualStudio\11.0_Config\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
-
for VS 2012. Use 12.0_Config for VS 2013.
-
Updating
-
Updating the component is very simple. Just modify the above registry keys by
-changing the version number.
-
Removing
-
To remove the component, delete the above registry keys. You should also
-remove the corresponding assembly from GAC.
-
Automating Integration with TCI using TciToolboxInstaller
-
I made a simple command-line application called TciToolboxInstaller
-which does all the described steps. The usage is simple:
-
TciToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
-
For example, if you like to install SampleControl.dll in Visual Studio 2012
-Toolbox, just call:
-
TciToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
-
You can use quotes for the last two parameters if they contain spaces.
-
The TciToolboxInstaller project is contained in sample
-source code.
-
-
Installing
-
The
-DTE (Development Tools Environment) approach does not require working
-with GAC or registry. It remotely manipulates Visual Studio Toolbox and
-adds/removes items as needed.
-
The whole installation is done from (managed) code using COM wrappers. It
-works in the following steps:
-
- - Check if an instance of Visual Studio is not running. If not, continue.
- - Retrieve an EnvDTE.DTE object corresponding to the
- version of Visual Studio we want to integrate with.
- - Create a "dummy" project using the DTE object
- - Obtain Toolbox window and ToolBox object from it.
- - Find or create ToolBoxTab object.
- - Add item in the Toolbox tab (ToolBoxTab.ToolBoxItems.Add).
- - Wait until current instance of Visual Studio stops running.
-
-
Here are some of the step/strongs in C# code - it is an excerpt from
-DteToolboxInstaller project provided in sample source code:
-
-// 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);
-}
-
-
There are several obstacles on implementing the DTE approach.
-
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.
-
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.
-
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
-DteToolboxInstaller (see below) source code, where is a working installer
-implemented that uses this approach.
-
Updating and Removing
-
Since we have full control over the Toolbox with this approach, updating or
-removing items/tabs is done with the corresponding DTE objects.
-
Automatic Integration with DTE using DteToolboxInstaller
-
I made a simple command-line application called DteToolboxInstaller
-which does all the necessary steps and solves the deals with the discussed
-obstacles. The usage is simple:
-
DteToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
-
For example, if you like to install SampleControl.dll in Visual Studio 2012
-Toolbox, just call:
-
DteToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
-
You can use quotes for the last two parameters if they contain spaces.
-
The DteToolboxInstaller project is contained in sample
-source code.
-
-
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.
-
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.
-
Creating the VSI Package
-
I have created an empty folder and copied SampleControl.dll in
-it. All that is needed to make a VSI package is to create a .VSCONTENT file,
-which is simply a XML file satisfying
-Visual Studio Content Installer schema:
-
-<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>
-
-
The content is readable and pretty straightforward. The
-ContentVersion 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).
-
Now we zip the two files and rename extension of the archive to .VSI. We
-should end up with the following three files:
-

-
If you double-click the SampleControl.vsi, the Visual Studio
-Content Installer opens up. You can start the installer from command line as
-well:
-
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
-
The installer have a form o wizard:
-

-
Signing the VSI Package
-
By default, the VSI package is not signed. This causes showing: "Publisher:
-Unknown" label on the first page of the installation wizard and an unpleasant
-dialog box later on:
-

-
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).
-
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 MakeZipExe
-to do this task:
-
MakeZipExe.exe -zipfile:SampleControl.vsi -output:SampleControl-unsigned.vsi -overwrite
-
The MakeZipExe tool is located at Visual Studio's binary
-folder:
-
c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MakeZipExe.exe
-
The second step is signing the .EXE file using signtool.exe.
-You can find signtool.exe in Microsoft Windows SDK, i.e.:
-
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe
-
Here is a sample usage of signtool.exe:
-
signtool.exe sign /du "http://www.componentowl.com/sample-control" /f certificate.pfx /p abc123 /t "http://timestamp.comodoca.com/authenticode" "SampleControl-signed.vsi"
-
When signed, the "Publisher" and "Information URL" 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).
-
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.
-WinZip).
-
Uninstalling the Control from Toolbox
-
As far as I know, the control cannot be removed from the Toolbox
-programmatically. You need to delete the control's DLL located at
-
c:\Users\<user>\Documents\Visual Studio 2010\Controls\
-
the same should be done for every version of Visual Studio installed.
-
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:
-
-
Drawbacks of Using VSI Package
-
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.
-
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.
-
You also cannot specify custom Toolbox tab. All controls are installed under
-"My Controls" tab:
-

-
-
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.
-
Although VSPackage and our sample control can be packed within the same
-assembly, we will create a separate Visual Studio Package project.
-
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).
-
Creating VSPackage Project
-
We would like to have our VSPackage compatible with VS 2010, 2012
-and 2013, so we will work in Visual Studio 2010.
-
Select "File - New - Project.." (Control+Shift+N) and
-select the "Visual Studio Package" template:
-
-
This will start a "Visual Studio Package Wizard":
-

-
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":
-

-

-
Now we will take a look on the generated files. Open the Guids.cs
-file:
-
-// Guids.cs
-// MUST match guids.h
-using System;
-
-namespace ComponentOwl.ToolboxIntegration
-{
- static class GuidList
- {
- public const string GuidSampleVSPackagePkgString = "00000000-8fdf-48b6-98f8-4ff21a3a4def";
- public const string GuidSampleVSPackageCmdSetString = "def6519d-5ace-4062-95d6-4ee43f4a5de9";
-
- public static readonly Guid GuidSampleVSPackageCmdSet = new Guid(GuidSampleVSPackageCmdSetString);
- };
-}
-
-
Here are the GUIDs 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.
-
You can also generate new GUIDs any time, for example using
-online GUID
-generator or guidgen.exe utility from Windows SDK. When these numbers are changed, your package will be different from
-Visual Studio's point of view.
-
Another important file here is source.extension.vsixmanifest.
-If you double-click on the file in Solution Explorer, the VSIX Manifest Designer
-will show up:
-

-
Not all the fields are mandatory, but I will fill all of them nevertheless:
-
- - ID - 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.
- - Product Name - This field is used for Toolbox Tab name,
- so I will put "Component Owl Controls" here.
- - Author - Your name or company name -
- "ComponentOwl.com", for example.
- - Version - 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.
- - Description - Speaks for itself.
- - Locale - Language for the package.
- - Supported VS Editions - 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.
- - Supported Framework Runtime - 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.
-
-
Adding Support for Visual Studio 2012/2013
-
We have specified supported Visual Studio Editions in VSIX Manifest Designer,
-through the "Visual Studio Version and Edition" dialog box:
-

-
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
-source.extensions.vsixmanifest file for manual editing. Select the file
-in Solution Explorer and press F7 (View Code):
-
-<?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>
- <VisualStudio Version="10.0">
- <Edition>Ultimate</Edition>
- <Edition>Premium</Edition>
- <Edition>Pro</Edition>
- </VisualStudio>
- </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>
-
-
Take a look on the Vsix/Identifier/SupportedProducts/VisualStudio
-element (highlighted in bold). Copy and paste this element and modify
-Version attribute on the second one to "11.0":
-
-<VisualStudio Version="11.0">
- <Edition>Ultimate</Edition>
- <Edition>Premium</Edition>
- <Edition>Pro</Edition>
-</VisualStudio>
-
-
The edition tags are valid for version 11.0 because Visual Studio 2012
-template generates the same edition names.
-
Writing Package Code
-
Now we will take a look on the VSPackage code itself. Open the
-SampleVSPackage.cs
-file. I kept only the necessary code and added the ProvideToolboxItems attribute:
-
-[PackageRegistration(UseManagedResourcesOnly = true)]
-[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
-[Guid(GuidList.guidSampleVsPackagePkgString)]
-[ProvideToolboxItems(1)]
-public sealed class SampleVsPackage : Package
-{
-}
-
-
Our VSPackage implementation inherits from
-Microsoft.VisualStudio.Shell.Package class and is decorated by three
-attributes:
-
- - PackageRegistrationAttribute - Specifies that package
- registration tool should look for additional attributes (will be discussed
- later).
- - InstalledProductRegistrationAttribute - Provides
- information for the Visual Studio splash screen and About box.
- - GuidAttribute - 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).
- - ProvideToolboxItemsAttribute - 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.
-
-
The strings "#110" and "#112" in
-InstalledProductRegistrationAttribute refer to keys in
-VSPackage.resx. You can open this file and edit package name and
-description there:
-

-
Now we write methods within SampleVsPackage class that work with the Toolbox:
-
-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);
-}
-
-
The method names InstallToolboxItems and
-RemoveToolboxItems
-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.
-
The ToolboxService class comes from
-System.Drawing.Design and we need to add reference to this asssembly in
-order to use ToolboxService.
-
Building the Package
-
Before building the SampleVsPackage project, open project
-properties, find the VSIX tab and uncheck all the options:
-

-
Finally, build the project. Just two files, SampleVsPackage.dll
-and SampleVsPackage.pdb, should be generated.
-
Registering the Package
-
Until the package can be loaded by Visual Studio, it needs to be
-registered.
-The registration is simply writing specific keys into Windows Registry.
-
To do that, find the Package Registration Utility (RegPkg.exe). It should be
-located in Visual Studio SDK directory, e.g.:
-
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
-
You can copy the tool where it suits you.
-
Here is a sample usage of RegPkg:
-
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
-
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.
-
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 /regfile parameter:
-
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
-
This creates SampleVsPackge.reg file you can use any time
-later instead of RegPkg.exe itself.
-
There are two other options for specifying how the package will be registered:
-codebase and assembly. When /codebase
-parameter is used (as in the sample above), the registry will point to the location on disk where your
-package is located (see
-
-Assembly.CodeBase property for more information).
-
Another option is the /assembly parameter - this assumbes
-that your VSPackage assembly is located in GAC (Global Assembly Cache). See
-section Installing the Control in GAC for more information.
-
You can check out the registry after the package registration:
-

-
Package Registration for Visual Studio 2012/2013
-
Regrettably, simply registering package is not enough for Visual Studio 2012/2013 to load
-it (see this
-
-blog post). Because of performance optimizations, VS developers removed
-feature that looks for changes in VS registry root and thus we need to call
-
devenv.exe /Setup
-
In order to finish package registration.
-
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).
-
We can speed things up by a little hack. One of the things the /Setup
-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.
-
The hive is located in
-HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config.
-
So let's open and edit the SampleVsPackage.reg file we have
-generated using RegPkg.exe earlier. Here is the modified version where only the
-registry root has been changed:
-
-REGEDIT4
-
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\InstalledProducts\SampleVsPackage]
-@="#110"
-"Package"="{00000000-8fdf-48b6-98f8-4ff21a3a4def}"
-"PID"="1.0"
-"ProductDetails"="#112"
-"LogoID"="#400"
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\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"
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}\Toolbox]
-"Default Items"=dword:00000001
-
-
The highlighted parts have been edited.
-
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.
-
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 "devenv.exe /Setup".
-
Loading VSPackage
-
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:
-

-
Displaying Your Extension in VS About Box
-
If you want information about your extension to be visible in Visual Studio
-splash screen and About Box, implement IVsInstalledProduct
-interface:
-
-...
-
-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;
- }
-
- ...
-
-}
-
-
This code causes the component to show up in the list of "Installed Products"
-in Visual Studio about box:
-

-
As for the splash screen, Visual Studio 2008 used to display extensions in
-its splash screen, but later version do not:
-
-
-
-
Troubleshooting Package Load Failures
-
You may encounter this dialog when playing with packages:
-

-
When you click "No", the package will be skipped later when loading packages.
-You can re-enable loading all packages by running
-
devenv.exe /ResetSkipPkgs
-
To debug package load problem, you can do just what the dialog says. Run
-
devenv.exe /log
-
and then take a look on the ActivityLog.xml (path is shown
-in the dialog). There you can find cause of the problem in one of the "entry"
-elements:
-
-...
-<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>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.</errorinfo>
-</entry>
-...
-
-
In this particular case, the problem was caused by changing output path from
-"bin\SampleVSPackage.dll" to "bin\Debug\SampleVSPackage.dll"
-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).
-
Past Troubles with Package Load Keys
-
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.
-
I believe PLK caused many troubles and headaches to developers, including
-myself.
-
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
-
Update Control Already Installed in Toolbox
-
Suppose we have already integrated SampleControl version 3.3.0.0 in the
-Visual Sudio Toolbox:
-

-
We would like to update this control to version 3.4.0.0.
-
First of all, we update assembly information of the SampleControl
-project:
-

-
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.
-
You don't need to increment assembly version of the SampleVsPackage project,
-but at least you have to increment parameter of the ProvideToolboxItems attribute:
-
-[PackageRegistration(UseManagedResourcesOnly = true)]
-[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
-[Guid(GuidList.guidSampleVsPackagePkgString)]
-[ProvideToolboxItems(2)]
-public sealed class SampleVsPackage : Package, IVsInstalledProduct
-{
- ...
-}
-
-
The package need to be re-registered (see section Registering the Package)
-which will effectively update just the "Default Items" value in the Toolbox key:
-

-
This will cause Visual Studio to update your control in the Toolbox:
-

-
Remove Control from the Toolbox
-
Now we would like to remove control from the Visual Studio Toolbox. This
-step can be done by custom uninstaller.
-
One way to do that is to simply unregister the VSPackage using
-RegPkg.exe:
-
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
-
You can also do this manually by simply removing the registry entry of the
-corresponding package, e.g.:
-
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}
-
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 Package Registration for Visual Studio 2012/2013.
-
-
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.
-
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.
-
Create a new Project from Template
-
If you have Visual Studio 2010 SDK installed, you can create a new VSIX
-package project with control from a template.
-
Select "File - New - Project.." (Control+Shift+N) and
-then select the "Windows Forms Toolbox Control" or "WPF
-Toolbox Control" template:
-

-
The projects is basically a VSPackage wrapped in VSIX container after
-build. The package assembly also contain the control class named
-ToolboxControl.
-
There are three important files generated by the template:
-
- - ProvideToolboxControlAttribute.cs - This is attribute
- for ToolboxControl class. We will discuss it later.
- - source.extension.vsixmanifest - This is manifest XML
- file for our VSIX package. It contains all information about the package and
- what it contains.
- - ToolboxControl.cs - This is a sample control to be
- installed in Visual Studio Toolbox.
-
-
Create a new Project from VSPackage
-
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 SampleVsixPackage and configure it according
-to "Windows Forms Toolbox Control" template to show you all the differences.
-
The basic configuration of source.extension.vsixmanifest is
-the same as in previous chapter.
-
Project properties differs from VSPackage we have created earlier on the VSIX
-tab, where we have the first two check boxes checked:
-

-
Update the Manifest File
-
Double-click on the source.extension.vsixmanifest file to
-open up the VSIX Manifest Designer:
-

-
If you are not sure about some part of the form, please take a look on
-section Create VSPackage Project, where the form is described in more
-detail.
-
In addition to previous VSPackage project, I have also filled the following
-optional boxes:
-
- - License Terms - If you have EULA or other licence in
- TXT or RTF format, you can browse for it.
- - Icon - You can browse for an icon representing the
- extension. It should be 32x32 pixels large, PNG, BMP, JPEG or ICO image
- format.
- - Preview Image - Thumbnail image representing the
- extension. It should be 200x200 pixels large, PNG, BMP or JPEG image format.
- - More Info URL - URL of a website containing more
- information about the extension.
- - Getting Started Guide - URL of a website with
- documentation; you can also provide relative path to HTML file with the
- local documentation.
-
-
Add Control
-
Let's create a new WPF control within the SampleVsixPackage
-project itself. I will name it SampleWpfControl to distinguish
-it from SampleControl we have created earlier.
-
To ensure our control will show up in Toolbox of Visual Studio 2012/2013, we have
-to decorate the SampleWpfControl class by
-ProvideToolboxControlAttribute:
-
-[ProvideToolboxControl("SampleWpfControl", true)]
-public partial class SampleWpfControl : UserControl
-{
- ...
-}
-
-
You also have to provide implementation of the attribute class:
-
-[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));
- }
- }
-}
-
-
This code is generated if you create project from template.
-
The project in Solution Explorer should look like this:
-
-
-
Adding Controls from Other Projects
-
What if we would like to use SampleControl.dll as in the VSI
-package scenario?
-
Of course, we can click "Add Content" in the VSIX Manifest designer and
-simply add "Toolbox Control" content from other project:
-

-
However, this is possible only if the SampleControl project
-itself is a package project!
-
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.
-
Setting Up VSIX Installer
-
The VSIX Installer tool (VsixInstaller.exe) is located in
-Visual Studio's binary folder:
-
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
-
You can hit F6 and Visual Studio will build your project to create
-SampleVsixPackage.vsix file. This is our VSIX package.
-
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.
-
The installation can fail in the very first step:
-

-
This problem appears if you have invalid manifest file. If this happen, open
-source.extension.vsixmanifest and fill in all missing data.
-Furthermore, you can check if the XML is valid according to
-VSIX Extension
-Schema.
-
Now we are able to rebuild and run the VSIX installer again:
-

-
Make the VSIX Package Compatible with Visual Studio 2012/2013
-
To make our VSIX package working with Visual Studio 2012 and newer, we need
-to manually update the manifest file. Select the
-source.extension.vsixmanifest file and press F7 (View Code):
-
-<?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>
- <VisualStudio Version="11.0">
- <Edition>Ultimate</Edition>
- <Edition>Premium</Edition>
- <Edition>Pro</Edition>
- </VisualStudio>
- <VisualStudio Version="12.0">
- <Edition>Ultimate</Edition>
- <Edition>Premium</Edition>
- <Edition>Pro</Edition>
- </VisualStudio>
- </SupportedProducts>
- <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="5.0" />
- </Identifier>
- <References />
- <Content>
- <ToolboxControl>|%CurrentProject%;PkgdefProjectOutputGroup|</ToolboxControl>
- </Content>
-</Vsix>
-
-
The bolded text have been added. I have simply added a new
-VisualStudio element with higher version and all the editions (they are
-relevant for VS 2012 and 2013 as its own template also generates these).
-
The VSIX installer will show Visual Studio 2012 options as
-well after this update (if installed, of course):
-

-
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.
-
A great advantage over VSI package is that installation of Toolbox control is
-really fast with VSIX.
-
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):
-

-
Signing the VSIX Package
-
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.
-
To sign a VSIX package, we need PackageSignatureManager from
-System.IO.Packaging (WindowsBase.dll). I made a simple command-line application called SignVsix (you can
-find it in sample source code) that takes three arguments (VSIX file path, PFX
-certificate path and password for the certificate):
-
-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);
- }
- }
-}
-
-
The usage is very simple:
-
SignVsix.exe SampleVsixPackage.vsix certificate.pfx abc123
-
When the file is signed, VSIX Installer shows label "Digital Signature:
-<Author Name>" on the first page:
-

-
Dissecting the VSIX Package
-
If you look on the project references, you can see reference to
-Microsoft.VisualStudio.Shell.Immutable.10. This reference points to
-Visual Studio 2010 SDK and we cannot expect this dependency present on end-user's machine. This
-library contains ProvideToolboxControlAttribute class, which is
-used by our ToolboxControl.
-
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 any control.
-
Let's take a look on the ToolboxControl.vsix. It is simply a
-ZIP archive containing the manifest, resources, ToolboxControl binary and a
-ToolboxControl.pkgdef 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.
-
Update Toolbox Control via VSIX Package
-
If you made changes to your control and want to re-install the package, an
-error message appear:
-

-
In order to provide an update, you need to increment version number in the
-VSIX manifest:
-

-
You can also increment version number in the Package class attribute, but
-this is not necessary for the VSIX to perform update:
-
-[InstalledProductRegistration("#110", "#112", "2.0", IconResourceID = 400)]
-[Guid(GuidList.guidSampleVsixPackagePkgString)]
-public sealed class SampleVsixPackage : Package
-{
- ...
-}
-
-
Of course, you can also increment version of the assembly.
-
Uninstall the VSIX Package
-
The VSIX Installer can be used to uninstall control from the Toolbox via
-/uninstall parameter followed by package ID (the constant located in
-Guids.cs: GuidList.guidSampleVsixPackagePkgString):
-
VSIXInstaller.exe /uninstall:e3dfd099-d0ab-4b8e-b26d-639032c29ad9
-
It is also possible to uninstall VSIX Package manually using
-Extension Manager (Tools - Extension Manager...). In Visual Studio
-2012/2013, the corresponding dialog is called Extensions and Updates
-(Tools - Extensions and Updates...).
-

-
Quiet Mode
-
Both installation and uninstallation can be performed in quiet mode by using /quiet parameter. This will suppress
-user interface of the installer, which is handy when you want to automate
-Toolbox control integration with your custom installer.
-
-
Since .NET Framework is backward-compatible, building a component on lowest
-possible framework ensures compatibility with higher versions as well.
-
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.
-
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.
-
The solution to this is to build several DLLs, each with different features
-and possibly different target frameworks. Then integrate all the assemblies.
-
This does not pose a problem when DTE 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").
-
When TCI 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.
-
The VSI and VSIX approaches require
-renaming the component or customizing Toolbox tab in the
-ProvideToolboxControlAttribute (see part Toolbox Control Integration using
-VSIX Packages for more information).
-
The VSPackage approach allows you to place all the versions
-in Visual Studio Toolbox under their respective tabs.
-
When manual approach is used, you can of course add each
-version of the assembly separately and also create separate tabs in the Toolbox.
-
-
-
-
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.
-
-
-Download sample source code (212 KB)
-
-
-
You can find the following folders in the archive:
-
DteToolboxInstaller - 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.
-
SampleControl - Windows Forms control for testing the
-integration.
-
SampleVsixPackage - 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.
-
SampleVsPackage - VSPackage that is able to install all
-control assemblies located in its own folder. Contains batch files for package
-registration/unregistration.
-
SignVsix - A command-line application for signing VSIX
-packages. Sample batch file is provided. Valid PFX certificate need to be
-provided by the user.
-
TciToolboxInstaller - 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.
-
VSI - Basic setting for creating VSI package and a sample
-VSI package created from the files. Batch file for signing the VSI package is
-provided.
-
-
-
-Download sample source code (212 KB)
-
-
+
+
+
+
+
The Most Complete Guide to Visual Studio Toolbox Control Integration
+
Libor
+Tinka, Lead Developer, ComponentOwl.com
+
+
+
Contents
+
1. Introduction
+2. Prerequisites
+3. Creating a Sample Control
+4. Manual Toolbox Integration
+5. Toolbox Integration using TCI
+6. Toolbox Integration using DTE
+7. Toolbox Integration using VSI Packages
+8. Toolbox Integration using VSPackages
+9. Toolbox Integration using VSIX Packages
+10. Supporting Multiple Version of .NET Framework
+11. Sample Source Code
+
+
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.
+
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.
+
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:
+
+ - How to install control in Visual Studio Toolbox?
+ - How to update the control?
+ - How to uninstall/remove the control?
+ - How to support multiple Visual Studio versions?
+
+
There are several options on how to integrate your controls with Visual
+Studio Toolbox:
+
+ - Manual installation
+ - Toolbox Control Installer (TCI)
+ - Visual Studio Automation Object Model (DTE)
+ - VSPackage
+ - VSI package
+ - VSIX package
+
+
Manual installation
+
The simplest way of adding control into Visual Studio Toolbox is from within
+the IDE.
+
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.
+
Advantages: zero effort
+Disadvantages: require experienced users, slows user
+producitivity, updating controls is not intuitive
+
Toolbox Control Installer (TCI)
+
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.
+
Advantages: simple and fast component installation, updating
+and removing
+Disadvantages: requires installation in GAC (not always
+wanted), VS 2005 supported with SDK only
+
Visual Studio Automation Object Model (DTE)
+
If you are not afraid of COM, you can try DTE (Development Tools Environment) approach.
+There is already a project on CodePlex called
+Visual Studio Toolbox Manager,
+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 DteToolboxInstaller, which
+is also a command-line application and does 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.
+
Advantages: does not require updating registry or GAC, full
+control over Toolbox
+Disadvantages: very slow, separate installation required for
+every version of Visual Studio
+
VSPackage
+
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.
+
Advantages: quick installation, appearance in About box and
+other extensibility features
+Disadvantages: cmplicated setup, each component requires its
+own package if shipped separately
+
VSI Package
+
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.
+
Advantages: simple creation, installer provided by Visual
+Studio, automated creation and signing requires several specific steps
+Disadvantages: no quiet mode (extra steps when custom installer
+is used), manual uninstallation
+
VSIX Package
+
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: "This extension does not contain a digital signature."
+Even better news: The VsixInstaller supports quiet mode!
+
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.
+
Advantages: installer provided by Visual Studio, quiet mode,
+fast installation
+Disadvantages: package project required, automated creation is
+complicated, no support for VS 2005 and 2008
+
Comparison of Approaches
+
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.
+
+
+ | |
+ 2005 |
+ 2008 |
+ 2010 |
+ 2012 |
+ 2013 |
+ Speed |
+ Install Automation |
+ Uninstall automation |
+
+
+ | Manual installation |
+  |
+  |
+  |
+  |
+  |
+ depends on user |
+  |
+  |
+
+
+ | TCI |
+  |
+  |
+  |
+  |
+  |
+ fast |
+  |
+ |
+
+
+ | EnvDTE |
+  |
+  |
+  |
+  |
+  |
+ slow |
+  |
+ |
+
+
+ | VSI |
+  |
+  |
+  |
+  |
+  |
+ moderate |
+  |
+ |
+
+
+ | VSIX |
+  |
+  |
+  |
+  |
+  |
+ moderate (faster than VSI) |
+  |
+ |
+
+
+ | VSPackage |
+  |
+  |
+  |
+  |
+  |
+ fast |
+  |
+ |
+
+
+
+
+
We will focus on integration with Visual Studio 2010, 2012 and 2013. Hence you will need:
+
+ - Visual Studio 2010 (or 2012, 2013)
+ - Visual Studio 2010 SDK (or 2012 SDK, 2013 SDK)
+ - Microsoft Windows SDK
+
+
The VS SDK contains regpkg.exe tool and project templates discussed in VSIX
+and VSPackage approaches.
+
The Windows SDK contains gacutil.exe, guidgen.exe, signtool.exe and other
+useful tools.
+
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:
+
+
+ | Release name |
+ Version number |
+
+
+ | Visual Studio 2005 |
+ 8.0 |
+
+
+ | Visual Studio 2008 |
+ 9.0 |
+
+
+ | Visual Studio 2010 |
+ 10.0 |
+
+
+ | Visual Studio 2012 |
+ 11.0 |
+
+
+ | Visual Studio 2013 |
+ 12.0 |
+
+
+
+
We will start by creating simple WinForms control for integration in VS
+Toolbox.
+
You can start with File - New - Project... (Control+Shift+N) and select
+Windows Forms Controls Library template.
+
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 Control will
+suffice.
+
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
+unless you use some feature specific to 4.5.
+
If you have multiple controls in your assembly and don't want to use some of
+them in Toolbox, decorate them with ToolboxItem attribute with
+defaultType parameter set to false:
+
+[ToolboxItem(false)]
+public class InvisibleControl : UserControl
+{
+ ...
+}
+
+
I have created a very simple control called SampleControl:
+

+
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).
+
Custom Transparent Icon for the Toolbox
+
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):
+

+
The icon file should have same name as the control class (i.e.
+SampleControl.BMP).
+
Finally, use ToolboxBitmapAttribute to link icon with the control class:
+
+[ToolboxBitmap(typeof(SampleControl), "Resources.SampleControl.bmp")]
+public partial class SampleControl : UserControl
+{
+ ...
+}
+
+
Note that icon location matters, at least in C#. Since I have added
+the icon under custom folder named Resources, I need to reference
+Resources.SampleControl.bmp instead of just SampleControl.bmp.
+
Here is the resulting transparent icon in Toolbox:
+

+
Marking the Control as Toolbox Item
+
We can mark control as toolbox item by adding a ToolboxItemAttribute
+with defaultType parameter set to true:
+
+[ToolboxItem(true)]
+public partial class SampleControl : UserControl
+...
+
+
This decoration is optional since the controls within assembly are
+considered toolbox items by default. However, we can mark certain control
+classes with ToolboxItem(false) 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.
+
Signing the Assembly
+
The assembly containing controls (SampleControl.dll 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.
+
To give an assembly a strong name, open project properties and find
+Signing tab:
+

+
Check the "Sign the assembly" option and select "<New...>"
+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).
+
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.
+
+
Installing
+
To install component into Visual Studio Toolbox manually, open some form or
+control in designer, open the Toolbox window (Control+Alt+X), right-click on the
+Toolbox window and select "Choose Items...":
+

+
The "Choose Toolbox Items" dialog will show up:
+

+
You can browse for DLL file with your component by clicking the "Browse..."
+button.
+
This is the simplest way of putting component in the Toolbox without extra
+actions required.
+
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.
+
Making the Control Visible in "Choose Toolbox Items" Dialog Box
+
As you can see on the above picture, the SampleControl component is already
+displayed in the dialog box under ".NET Framework Components" tab.
+
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.
+
You can register your own assembly this way by creating a key in registry:
+
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\<your control name>
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\<your control name>
+
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):
+
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
+
In both cases, the default value for the key is a string with full path to
+the folder with your assembly.
+
You can specify Toolbox tab in which the component should show up by adding
+subkey named "Toolbox" with single string value "TabName" 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:
+
+
+
The control should also appear in "Choose Toolbox Items" dialog box if it
+is installed in Global Assembly Cache.
+
The control pops up in the Toolbox automatically in
+its own tab in Visual Studio 2012/2013.
+
Installing the Control in GAC
+
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).
+
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 true 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.
+
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.
+
You can work with GAC by using tool called gacutil.exe or
+from code. We will discuss both approaches.
+
The gacutil.exe is located in Microsoft Windows SDK directory. There are two
+such extecutables:
+
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
+
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.
+
You can install an assembly to GAC by calling:
+
gacutil.exe /i SampleControl.dll
+
To uninstall it, we refer to our assembly by its assembly name, not file
+name:
+
gacutil.exe /u SampleControl
+
Finally, you can check if the assembly is installed in GAC by listing any
+instances of the provided name:
+
gacutil.exe /l SampleControl
+
It is not wise, however, to use gacutil.exe from a custom
+installer as it is located in SDK that user might not have installed.
+Furthermore, the SDK license does not allow bundling gacutil.exe
+with your installer.
+
Some installers like Inno Setup or MSI allow installing in GAC anyway.
+
You can also work with GAC using
+System.EnterpriseServices.Internal.Publish class. The class have two
+methods: GacInstall and GacRemove. Both
+methods take just path to assembly file as a parameter, so for example:
+
(new Publish()).GacInstall(assemblyPath);
+
will install the specified assembly in GAC.
+
Updating
+
Updating the control depends on how it is installed and referenced.
+
If you have added component in the Toolbox manually via "Choose Toolbox Items"
+dialog box and "Browse..." button, i.e. as a file reference, 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
+true in reference properties window; the default is
+false in this case). Simply replacing the DLL with the control by a newer
+file will suffice. If the user have specified "Specific Version" to true,
+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.
+
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 true by default:
+

+
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.
+
If you remove all versions of the component from GAC (e.g. using
+gacutil.exe) and then install just the newest one, the build will break
+unless the user changed "Specific Version" property to false.
+
Removing
+
Removing the manually installed control consists of just reverting all the
+steps done during the installation.
+
In case of file references, deleting the file is sufficient.
+
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 gacutil.exe).
+
Resetting Toolbox and Clearing the Toolbox Cache
+
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.
+
To do that, right-click on the Toolbox window and select "Reset
+Toolbox". Visual Studio will go through all the installed packages and reloads
+components into the Toolbox.
+
If this won't help, you can perform hard reset of the Toolbox. Exit
+Visual Studio and delete all .TBD files in the following folder:
+
\Users\<user>\AppData\Local\Microsoft\VisualStudio\10.0\
+
It should be up to four files:
+

+
Once removed, start Visual Studio again. After showing the Toolbox, all items
+should load instead of loading only the cached versions.
+
+
Installing
+
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.
+
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:
+
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
+
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).
+
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.
+
The installation consists of putting the control in GAC (see previous
+section for more information) and creating registry keys.
+
Suppose we have the SampleControl installed in GAC:
+

+
We will make reference to this assembly from registry by creating the
+following key:
+
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
+
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".
+
Installing in Visual Studio 2012 and 2013
+
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.:
+
HKCU\Software\Microsoft\VisualStudio\11.0_Config\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
+
for VS 2012. Use 12.0_Config for VS 2013.
+
Updating
+
Updating the component is very simple. Just modify the above registry keys by
+changing the version number.
+
Removing
+
To remove the component, delete the above registry keys. You should also
+remove the corresponding assembly from GAC.
+
Automating Integration with TCI using TciToolboxInstaller
+
I made a simple command-line application called TciToolboxInstaller
+which does all the described steps. The usage is simple:
+
TciToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
+
For example, if you like to install SampleControl.dll in Visual Studio 2012
+Toolbox, just call:
+
TciToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
+
You can use quotes for the last two parameters if they contain spaces.
+
The TciToolboxInstaller project is contained in sample
+source code.
+
+
Installing
+
The
+DTE (Development Tools Environment) approach does not require working
+with GAC or registry. It remotely manipulates Visual Studio Toolbox and
+adds/removes items as needed.
+
The whole installation is done from (managed) code using COM wrappers. It
+works in the following steps:
+
+ - Check if an instance of Visual Studio is not running. If not, continue.
+ - Retrieve an EnvDTE.DTE object corresponding to the
+ version of Visual Studio we want to integrate with.
+ - Create a "dummy" project using the DTE object
+ - Obtain Toolbox window and ToolBox object from it.
+ - Find or create ToolBoxTab object.
+ - Add item in the Toolbox tab (ToolBoxTab.ToolBoxItems.Add).
+ - Wait until current instance of Visual Studio stops running.
+
+
Here are some of the step/strongs in C# code - it is an excerpt from
+DteToolboxInstaller project provided in sample source code:
+
+// 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);
+}
+
+
There are several obstacles on implementing the DTE approach.
+
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.
+
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.
+
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
+DteToolboxInstaller (see below) source code, where is a working installer
+implemented that uses this approach.
+
Updating and Removing
+
Since we have full control over the Toolbox with this approach, updating or
+removing items/tabs is done with the corresponding DTE objects.
+
Automatic Integration with DTE using DteToolboxInstaller
+
I made a simple command-line application called DteToolboxInstaller
+which does all the necessary steps and solves the deals with the discussed
+obstacles. The usage is simple:
+
DteToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
+
For example, if you like to install SampleControl.dll in Visual Studio 2012
+Toolbox, just call:
+
DteToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
+
You can use quotes for the last two parameters if they contain spaces.
+
The DteToolboxInstaller project is contained in sample
+source code.
+
+
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.
+
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.
+
Creating the VSI Package
+
I have created an empty folder and copied SampleControl.dll in
+it. All that is needed to make a VSI package is to create a .VSCONTENT file,
+which is simply a XML file satisfying
+Visual Studio Content Installer schema:
+
+<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>
+
+
The content is readable and pretty straightforward. The
+ContentVersion 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).
+
Now we zip the two files and rename extension of the archive to .VSI. We
+should end up with the following three files:
+

+
If you double-click the SampleControl.vsi, the Visual Studio
+Content Installer opens up. You can start the installer from command line as
+well:
+
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
+
The installer have a form o wizard:
+

+
Signing the VSI Package
+
By default, the VSI package is not signed. This causes showing: "Publisher:
+Unknown" label on the first page of the installation wizard and an unpleasant
+dialog box later on:
+

+
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).
+
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 MakeZipExe
+to do this task:
+
MakeZipExe.exe -zipfile:SampleControl.vsi -output:SampleControl-unsigned.vsi -overwrite
+
The MakeZipExe tool is located at Visual Studio's binary
+folder:
+
c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MakeZipExe.exe
+
The second step is signing the .EXE file using signtool.exe.
+You can find signtool.exe in Microsoft Windows SDK, i.e.:
+
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe
+
Here is a sample usage of signtool.exe:
+
signtool.exe sign /du "http://www.componentowl.com/sample-control" /f certificate.pfx /p abc123 /t "http://timestamp.comodoca.com/authenticode" "SampleControl-signed.vsi"
+
When signed, the "Publisher" and "Information URL" 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).
+
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.
+WinZip).
+
Uninstalling the Control from Toolbox
+
As far as I know, the control cannot be removed from the Toolbox
+programmatically. You need to delete the control's DLL located at
+
c:\Users\<user>\Documents\Visual Studio 2010\Controls\
+
the same should be done for every version of Visual Studio installed.
+
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:
+
+
Drawbacks of Using VSI Package
+
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.
+
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.
+
You also cannot specify custom Toolbox tab. All controls are installed under
+"My Controls" tab:
+

+
+
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.
+
Although VSPackage and our sample control can be packed within the same
+assembly, we will create a separate Visual Studio Package project.
+
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).
+
Creating VSPackage Project
+
We would like to have our VSPackage compatible with VS 2010, 2012
+and 2013, so we will work in Visual Studio 2010.
+
Select "File - New - Project.." (Control+Shift+N) and
+select the "Visual Studio Package" template:
+
+
This will start a "Visual Studio Package Wizard":
+

+
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":
+

+

+
Now we will take a look on the generated files. Open the Guids.cs
+file:
+
+// Guids.cs
+// MUST match guids.h
+using System;
+
+namespace ComponentOwl.ToolboxIntegration
+{
+ static class GuidList
+ {
+ public const string GuidSampleVSPackagePkgString = "00000000-8fdf-48b6-98f8-4ff21a3a4def";
+ public const string GuidSampleVSPackageCmdSetString = "def6519d-5ace-4062-95d6-4ee43f4a5de9";
+
+ public static readonly Guid GuidSampleVSPackageCmdSet = new Guid(GuidSampleVSPackageCmdSetString);
+ };
+}
+
+
Here are the GUIDs 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.
+
You can also generate new GUIDs any time, for example using
+online GUID
+generator or guidgen.exe utility from Windows SDK. When these numbers are changed, your package will be different from
+Visual Studio's point of view.
+
Another important file here is source.extension.vsixmanifest.
+If you double-click on the file in Solution Explorer, the VSIX Manifest Designer
+will show up:
+

+
Not all the fields are mandatory, but I will fill all of them nevertheless:
+
+ - ID - 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.
+ - Product Name - This field is used for Toolbox Tab name,
+ so I will put "Component Owl Controls" here.
+ - Author - Your name or company name -
+ "ComponentOwl.com", for example.
+ - Version - 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.
+ - Description - Speaks for itself.
+ - Locale - Language for the package.
+ - Supported VS Editions - 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.
+ - Supported Framework Runtime - 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.
+
+
Adding Support for Visual Studio 2012/2013
+
We have specified supported Visual Studio Editions in VSIX Manifest Designer,
+through the "Visual Studio Version and Edition" dialog box:
+

+
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
+source.extensions.vsixmanifest file for manual editing. Select the file
+in Solution Explorer and press F7 (View Code):
+
+<?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>
+ <VisualStudio Version="10.0">
+ <Edition>Ultimate</Edition>
+ <Edition>Premium</Edition>
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ </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>
+
+
Take a look on the Vsix/Identifier/SupportedProducts/VisualStudio
+element (highlighted in bold). Copy and paste this element and modify
+Version attribute on the second one to "11.0":
+
+<VisualStudio Version="11.0">
+ <Edition>Ultimate</Edition>
+ <Edition>Premium</Edition>
+ <Edition>Pro</Edition>
+</VisualStudio>
+
+
The edition tags are valid for version 11.0 because Visual Studio 2012
+template generates the same edition names.
+
Writing Package Code
+
Now we will take a look on the VSPackage code itself. Open the
+SampleVSPackage.cs
+file. I kept only the necessary code and added the ProvideToolboxItems attribute:
+
+[PackageRegistration(UseManagedResourcesOnly = true)]
+[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+[Guid(GuidList.guidSampleVsPackagePkgString)]
+[ProvideToolboxItems(1)]
+public sealed class SampleVsPackage : Package
+{
+}
+
+
Our VSPackage implementation inherits from
+Microsoft.VisualStudio.Shell.Package class and is decorated by three
+attributes:
+
+ - PackageRegistrationAttribute - Specifies that package
+ registration tool should look for additional attributes (will be discussed
+ later).
+ - InstalledProductRegistrationAttribute - Provides
+ information for the Visual Studio splash screen and About box.
+ - GuidAttribute - 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).
+ - ProvideToolboxItemsAttribute - 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.
+
+
The strings "#110" and "#112" in
+InstalledProductRegistrationAttribute refer to keys in
+VSPackage.resx. You can open this file and edit package name and
+description there:
+

+
Now we write methods within SampleVsPackage class that work with the Toolbox:
+
+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);
+}
+
+
The method names InstallToolboxItems and
+RemoveToolboxItems
+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.
+
The ToolboxService class comes from
+System.Drawing.Design and we need to add reference to this asssembly in
+order to use ToolboxService.
+
Building the Package
+
Before building the SampleVsPackage project, open project
+properties, find the VSIX tab and uncheck all the options:
+

+
Finally, build the project. Just two files, SampleVsPackage.dll
+and SampleVsPackage.pdb, should be generated.
+
Registering the Package
+
Until the package can be loaded by Visual Studio, it needs to be
+registered.
+The registration is simply writing specific keys into Windows Registry.
+
To do that, find the Package Registration Utility (RegPkg.exe). It should be
+located in Visual Studio SDK directory, e.g.:
+
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
+
You can copy the tool where it suits you.
+
Here is a sample usage of RegPkg:
+
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
+
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.
+
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 /regfile parameter:
+
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
+
This creates SampleVsPackge.reg file you can use any time
+later instead of RegPkg.exe itself.
+
There are two other options for specifying how the package will be registered:
+codebase and assembly. When /codebase
+parameter is used (as in the sample above), the registry will point to the location on disk where your
+package is located (see
+
+Assembly.CodeBase property for more information).
+
Another option is the /assembly parameter - this assumbes
+that your VSPackage assembly is located in GAC (Global Assembly Cache). See
+section Installing the Control in GAC for more information.
+
You can check out the registry after the package registration:
+

+
Package Registration for Visual Studio 2012/2013
+
Regrettably, simply registering package is not enough for Visual Studio 2012/2013 to load
+it (see this
+
+blog post). Because of performance optimizations, VS developers removed
+feature that looks for changes in VS registry root and thus we need to call
+
devenv.exe /Setup
+
In order to finish package registration.
+
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).
+
We can speed things up by a little hack. One of the things the /Setup
+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.
+
The hive is located in
+HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config.
+
So let's open and edit the SampleVsPackage.reg file we have
+generated using RegPkg.exe earlier. Here is the modified version where only the
+registry root has been changed:
+
+REGEDIT4
+
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\InstalledProducts\SampleVsPackage]
+@="#110"
+"Package"="{00000000-8fdf-48b6-98f8-4ff21a3a4def}"
+"PID"="1.0"
+"ProductDetails"="#112"
+"LogoID"="#400"
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\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"
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}\Toolbox]
+"Default Items"=dword:00000001
+
+
The highlighted parts have been edited.
+
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.
+
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 "devenv.exe /Setup".
+
Loading VSPackage
+
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:
+

+
Displaying Your Extension in VS About Box
+
If you want information about your extension to be visible in Visual Studio
+splash screen and About Box, implement IVsInstalledProduct
+interface:
+
+...
+
+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;
+ }
+
+ ...
+
+}
+
+
This code causes the component to show up in the list of "Installed Products"
+in Visual Studio about box:
+

+
As for the splash screen, Visual Studio 2008 used to display extensions in
+its splash screen, but later version do not:
+
+
+
+
Troubleshooting Package Load Failures
+
You may encounter this dialog when playing with packages:
+

+
When you click "No", the package will be skipped later when loading packages.
+You can re-enable loading all packages by running
+
devenv.exe /ResetSkipPkgs
+
To debug package load problem, you can do just what the dialog says. Run
+
devenv.exe /log
+
and then take a look on the ActivityLog.xml (path is shown
+in the dialog). There you can find cause of the problem in one of the "entry"
+elements:
+
+...
+<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>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.</errorinfo>
+</entry>
+...
+
+
In this particular case, the problem was caused by changing output path from
+"bin\SampleVSPackage.dll" to "bin\Debug\SampleVSPackage.dll"
+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).
+
Past Troubles with Package Load Keys
+
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.
+
I believe PLK caused many troubles and headaches to developers, including
+myself.
+
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
+
Update Control Already Installed in Toolbox
+
Suppose we have already integrated SampleControl version 3.3.0.0 in the
+Visual Sudio Toolbox:
+

+
We would like to update this control to version 3.4.0.0.
+
First of all, we update assembly information of the SampleControl
+project:
+

+
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.
+
You don't need to increment assembly version of the SampleVsPackage project,
+but at least you have to increment parameter of the ProvideToolboxItems attribute:
+
+[PackageRegistration(UseManagedResourcesOnly = true)]
+[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+[Guid(GuidList.guidSampleVsPackagePkgString)]
+[ProvideToolboxItems(2)]
+public sealed class SampleVsPackage : Package, IVsInstalledProduct
+{
+ ...
+}
+
+
The package need to be re-registered (see section Registering the Package)
+which will effectively update just the "Default Items" value in the Toolbox key:
+

+
This will cause Visual Studio to update your control in the Toolbox:
+

+
Remove Control from the Toolbox
+
Now we would like to remove control from the Visual Studio Toolbox. This
+step can be done by custom uninstaller.
+
One way to do that is to simply unregister the VSPackage using
+RegPkg.exe:
+
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
+
You can also do this manually by simply removing the registry entry of the
+corresponding package, e.g.:
+
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}
+
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 Package Registration for Visual Studio 2012/2013.
+
+
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.
+
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.
+
Create a new Project from Template
+
If you have Visual Studio 2010 SDK installed, you can create a new VSIX
+package project with control from a template.
+
Select "File - New - Project.." (Control+Shift+N) and
+then select the "Windows Forms Toolbox Control" or "WPF
+Toolbox Control" template:
+

+
The projects is basically a VSPackage wrapped in VSIX container after
+build. The package assembly also contain the control class named
+ToolboxControl.
+
There are three important files generated by the template:
+
+ - ProvideToolboxControlAttribute.cs - This is attribute
+ for ToolboxControl class. We will discuss it later.
+ - source.extension.vsixmanifest - This is manifest XML
+ file for our VSIX package. It contains all information about the package and
+ what it contains.
+ - ToolboxControl.cs - This is a sample control to be
+ installed in Visual Studio Toolbox.
+
+
Create a new Project from VSPackage
+
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 SampleVsixPackage and configure it according
+to "Windows Forms Toolbox Control" template to show you all the differences.
+
The basic configuration of source.extension.vsixmanifest is
+the same as in previous chapter.
+
Project properties differs from VSPackage we have created earlier on the VSIX
+tab, where we have the first two check boxes checked:
+

+
Update the Manifest File
+
Double-click on the source.extension.vsixmanifest file to
+open up the VSIX Manifest Designer:
+

+
If you are not sure about some part of the form, please take a look on
+section Create VSPackage Project, where the form is described in more
+detail.
+
In addition to previous VSPackage project, I have also filled the following
+optional boxes:
+
+ - License Terms - If you have EULA or other licence in
+ TXT or RTF format, you can browse for it.
+ - Icon - You can browse for an icon representing the
+ extension. It should be 32x32 pixels large, PNG, BMP, JPEG or ICO image
+ format.
+ - Preview Image - Thumbnail image representing the
+ extension. It should be 200x200 pixels large, PNG, BMP or JPEG image format.
+ - More Info URL - URL of a website containing more
+ information about the extension.
+ - Getting Started Guide - URL of a website with
+ documentation; you can also provide relative path to HTML file with the
+ local documentation.
+
+
Add Control
+
Let's create a new WPF control within the SampleVsixPackage
+project itself. I will name it SampleWpfControl to distinguish
+it from SampleControl we have created earlier.
+
To ensure our control will show up in Toolbox of Visual Studio 2012/2013, we have
+to decorate the SampleWpfControl class by
+ProvideToolboxControlAttribute:
+
+[ProvideToolboxControl("SampleWpfControl", true)]
+public partial class SampleWpfControl : UserControl
+{
+ ...
+}
+
+
You also have to provide implementation of the attribute class:
+
+[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));
+ }
+ }
+}
+
+
This code is generated if you create project from template.
+
The project in Solution Explorer should look like this:
+
+
+
Adding Controls from Other Projects
+
What if we would like to use SampleControl.dll as in the VSI
+package scenario?
+
Of course, we can click "Add Content" in the VSIX Manifest designer and
+simply add "Toolbox Control" content from other project:
+

+
However, this is possible only if the SampleControl project
+itself is a package project!
+
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.
+
Setting Up VSIX Installer
+
The VSIX Installer tool (VsixInstaller.exe) is located in
+Visual Studio's binary folder:
+
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
+
You can hit F6 and Visual Studio will build your project to create
+SampleVsixPackage.vsix file. This is our VSIX package.
+
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.
+
The installation can fail in the very first step:
+

+
This problem appears if you have invalid manifest file. If this happen, open
+source.extension.vsixmanifest and fill in all missing data.
+Furthermore, you can check if the XML is valid according to
+VSIX Extension
+Schema.
+
Now we are able to rebuild and run the VSIX installer again:
+

+
Make the VSIX Package Compatible with Visual Studio 2012/2013
+
To make our VSIX package working with Visual Studio 2012 and newer, we need
+to manually update the manifest file. Select the
+source.extension.vsixmanifest file and press F7 (View Code):
+
+<?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>
+ <VisualStudio Version="11.0">
+ <Edition>Ultimate</Edition>
+ <Edition>Premium</Edition>
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="12.0">
+ <Edition>Ultimate</Edition>
+ <Edition>Premium</Edition>
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ </SupportedProducts>
+ <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="5.0" />
+ </Identifier>
+ <References />
+ <Content>
+ <ToolboxControl>|%CurrentProject%;PkgdefProjectOutputGroup|</ToolboxControl>
+ </Content>
+</Vsix>
+
+
The bolded text have been added. I have simply added a new
+VisualStudio element with higher version and all the editions (they are
+relevant for VS 2012 and 2013 as its own template also generates these).
+
The VSIX installer will show Visual Studio 2012 options as
+well after this update (if installed, of course):
+

+
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.
+
A great advantage over VSI package is that installation of Toolbox control is
+really fast with VSIX.
+
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):
+

+
Signing the VSIX Package
+
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.
+
To sign a VSIX package, we need PackageSignatureManager from
+System.IO.Packaging (WindowsBase.dll). I made a simple command-line application called SignVsix (you can
+find it in sample source code) that takes three arguments (VSIX file path, PFX
+certificate path and password for the certificate):
+
+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);
+ }
+ }
+}
+
+
The usage is very simple:
+
SignVsix.exe SampleVsixPackage.vsix certificate.pfx abc123
+
When the file is signed, VSIX Installer shows label "Digital Signature:
+<Author Name>" on the first page:
+

+
Dissecting the VSIX Package
+
If you look on the project references, you can see reference to
+Microsoft.VisualStudio.Shell.Immutable.10. This reference points to
+Visual Studio 2010 SDK and we cannot expect this dependency present on end-user's machine. This
+library contains ProvideToolboxControlAttribute class, which is
+used by our ToolboxControl.
+
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 any control.
+
Let's take a look on the ToolboxControl.vsix. It is simply a
+ZIP archive containing the manifest, resources, ToolboxControl binary and a
+ToolboxControl.pkgdef 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.
+
Update Toolbox Control via VSIX Package
+
If you made changes to your control and want to re-install the package, an
+error message appear:
+

+
In order to provide an update, you need to increment version number in the
+VSIX manifest:
+

+
You can also increment version number in the Package class attribute, but
+this is not necessary for the VSIX to perform update:
+
+[InstalledProductRegistration("#110", "#112", "2.0", IconResourceID = 400)]
+[Guid(GuidList.guidSampleVsixPackagePkgString)]
+public sealed class SampleVsixPackage : Package
+{
+ ...
+}
+
+
Of course, you can also increment version of the assembly.
+
Uninstall the VSIX Package
+
The VSIX Installer can be used to uninstall control from the Toolbox via
+/uninstall parameter followed by package ID (the constant located in
+Guids.cs: GuidList.guidSampleVsixPackagePkgString):
+
VSIXInstaller.exe /uninstall:e3dfd099-d0ab-4b8e-b26d-639032c29ad9
+
It is also possible to uninstall VSIX Package manually using
+Extension Manager (Tools - Extension Manager...). In Visual Studio
+2012/2013, the corresponding dialog is called Extensions and Updates
+(Tools - Extensions and Updates...).
+

+
Quiet Mode
+
Both installation and uninstallation can be performed in quiet mode by using /quiet parameter. This will suppress
+user interface of the installer, which is handy when you want to automate
+Toolbox control integration with your custom installer.
+
+
Since .NET Framework is backward-compatible, building a component on lowest
+possible framework ensures compatibility with higher versions as well.
+
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.
+
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.
+
The solution to this is to build several DLLs, each with different features
+and possibly different target frameworks. Then integrate all the assemblies.
+
This does not pose a problem when DTE 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").
+
When TCI 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.
+
The VSI and VSIX approaches require
+renaming the component or customizing Toolbox tab in the
+ProvideToolboxControlAttribute (see part Toolbox Control Integration using
+VSIX Packages for more information).
+
The VSPackage approach allows you to place all the versions
+in Visual Studio Toolbox under their respective tabs.
+
When manual approach is used, you can of course add each
+version of the assembly separately and also create separate tabs in the Toolbox.
+
+
+
+
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.
+
+
+Download sample source code (212 KB)
+
+
+
You can find the following folders in the archive:
+
DteToolboxInstaller - 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.
+
SampleControl - Windows Forms control for testing the
+integration.
+
SampleVsixPackage - 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.
+
SampleVsPackage - VSPackage that is able to install all
+control assemblies located in its own folder. Contains batch files for package
+registration/unregistration.
+
SignVsix - A command-line application for signing VSIX
+packages. Sample batch file is provided. Valid PFX certificate need to be
+provided by the user.
+
TciToolboxInstaller - 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.
+
VSI - Basic setting for creating VSI package and a sample
+VSI package created from the files. Batch file for signing the VSI package is
+provided.
+
+
+
+Download sample source code (212 KB)
+
+

This work is licensed under a
Creative Commons Attribution 3.0 Unported License.Component Owl WinForms - .NET 2.0
@@ -1668,7 +1668,7 @@ provided.
-
+
diff --git a/src/data/better-listview-express/comparison-with-full-version.html b/src/data/better-listview-express/comparison-with-full-version.html
index 95a9675..b3ff78a 100644
--- a/src/data/better-listview-express/comparison-with-full-version.html
+++ b/src/data/better-listview-express/comparison-with-full-version.html
@@ -41,16 +41,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_