├── .gitattributes ├── .gitignore ├── IntegrationTests.testsettings ├── License.txt ├── README.md ├── Screenshot.png ├── SmartPaster2013.sln ├── SmartPaster2013 ├── GlobalSuppressions.cs ├── Guids.cs ├── Key.snk ├── PkgCmdID.cs ├── Properties │ └── AssemblyInfo.cs ├── ReplaceForm.Designer.cs ├── ReplaceForm.cs ├── ReplaceForm.resx ├── Resources.Designer.cs ├── Resources.resx ├── Resources │ ├── Images.png │ ├── Package.ico │ └── Paste_6520.png ├── SmartFormatter.cs ├── SmartPaster.cs ├── SmartPaster2013.csproj ├── SmartPaster2013.vsct ├── SmartPaster2013Package.cs ├── SmartPaster2013_IntegrationTests │ ├── IntegrationTest Library │ │ ├── DialogboxPurger.cs │ │ ├── NativeMethods.cs │ │ └── Utils.cs │ ├── Key.snk │ ├── MenuItemTest.cs │ ├── PackageTest.cs │ ├── SignOff-Tests │ │ ├── CPPProjectTests.cs │ │ ├── CSharpProjectTests.cs │ │ ├── SolutionTests.cs │ │ └── VBProjectTests.cs │ └── SmartPaster2013_IntegrationTests.csproj ├── SmartPaster2013_UnitTests │ ├── Key.snk │ ├── MenuItemTests │ │ ├── MenuItemCallback.cs │ │ └── UIShellServiceMock.cs │ ├── PackageTest.cs │ ├── Scratchpad.vb │ ├── SmartFormatterTests.cs │ ├── SmartPaster2013_UnitTests.csproj │ ├── app.config │ └── packages.config ├── VSPackage.resx ├── app.config ├── packages.config └── source.extension.vsixmanifest └── UnitTests.testsettings /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | .vs/ 53 | 54 | # MSTest test Results 55 | [Tt]est[Rr]esult*/ 56 | [Bb]uild[Ll]og.* 57 | 58 | *_i.c 59 | *_p.c 60 | *.ilk 61 | *.meta 62 | *.obj 63 | *.pch 64 | *.pdb 65 | *.pgc 66 | *.pgd 67 | *.rsp 68 | *.sbr 69 | *.tlb 70 | *.tli 71 | *.tlh 72 | *.tmp 73 | *.tmp_proj 74 | *.log 75 | *.vspscc 76 | *.vssscc 77 | .builds 78 | *.pidb 79 | *.log 80 | *.scc 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opensdf 87 | *.sdf 88 | *.cachefile 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | *.ncrunch* 110 | .*crunch*.local.xml 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.Publish.xml 130 | *.pubxml 131 | 132 | # NuGet Packages Directory 133 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 134 | packages/ 135 | 136 | # Windows Azure Build Output 137 | csx 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.[Pp]ublish.xml 152 | *.pfx 153 | *.publishsettings 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | App_Data/*.mdf 167 | App_Data/*.ldf 168 | 169 | ############# 170 | ## Windows detritus 171 | ############# 172 | 173 | # Windows image file caches 174 | Thumbs.db 175 | ehthumbs.db 176 | 177 | # Folder config file 178 | Desktop.ini 179 | 180 | # Recycle Bin used on file shares 181 | $RECYCLE.BIN/ 182 | 183 | # Mac crap 184 | .DS_Store 185 | 186 | 187 | ############# 188 | ## Python 189 | ############# 190 | 191 | *.py[co] 192 | 193 | # Packages 194 | *.egg 195 | *.egg-info 196 | dist/ 197 | build/ 198 | eggs/ 199 | parts/ 200 | var/ 201 | sdist/ 202 | develop-eggs/ 203 | .installed.cfg 204 | 205 | # Installer logs 206 | pip-log.txt 207 | 208 | # Unit test / coverage reports 209 | .coverage 210 | .tox 211 | 212 | #Translations 213 | *.mo 214 | 215 | #Mr Developer 216 | .mr.developer.cfg 217 | -------------------------------------------------------------------------------- /IntegrationTests.testsettings: -------------------------------------------------------------------------------- 1 | 2 | 7 | This test run configuration uses the VS IDE host type in the test run. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013 Martin J Willey 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SmartPaster 2013/2015/2017/2019 2 | 3 | A port of Alex Papadimoulis' Smart Paster for Visual Studio 2013, 2015 and 2017. 4 | (via SmartPaster 2010 for Visual Studio 2010 and 2012: https://smartpaster2010.codeplex.com/) 5 | 6 | For VS 2022, see https://github.com/martinjw/SmartPaster (marketplace: https://marketplace.visualstudio.com/items?itemName=martinw.SmartPaster ) 7 | 8 | A "Paste As" right-click option that allows clipboard text to be: 9 | 10 | * Paste as Comment 11 | * Paste as Literal String (regular string literal) 12 | * Paste as @String (in C#, verbatim string; in VB, CData or VB14 multi-line strings depending on version) 13 | * Paste as StringBuilder 14 | * Paste as Byte Array 15 | 16 | On Visual Studio Gallery: 17 | http://visualstudiogallery.msdn.microsoft.com/0611a238-7405-4d5f-ace0-5b3d5cf325e0 18 | 19 | v1.1 adds Unicode, VS2015 support, both regular and verbatim strings. 20 | v1.2 adds Paste as Byte Array, C++ support (thanks to leg0) 21 | v1.3 adds VS2017 support, renamed to SmartPaster2017 22 | 23 | ![Screenshot](Screenshot.png?raw=true) 24 | 25 | SmartPaster 2010 Codeplex version (VS2010, VS2012): 26 | https://smartpaster2010.codeplex.com/ 27 | 28 | ## Credits 29 | 30 | The original SmartPaster (for VS 2003/2005/2008) by Alex Papadimoulis is here: http://weblogs.asp.net/alex_papadimoulis/archive/2004/05/25/Smart-Paster-1.1-Add-In---StringBuilder-and-Better-C_2300_-Handling.aspx 31 | The original source code is here: http://code.google.com/p/smartpaster/ 32 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/Screenshot.png -------------------------------------------------------------------------------- /SmartPaster2013.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26206.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartPaster2013", "SmartPaster2013\SmartPaster2013.csproj", "{E4C30299-C9D8-4860-BBB0-02F5887D3ED2}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2DC34759-FCD8-4627-B701-48F17B531123}" 9 | ProjectSection(SolutionItems) = preProject 10 | IntegrationTests.testsettings = IntegrationTests.testsettings 11 | License.txt = License.txt 12 | UnitTests.testsettings = UnitTests.testsettings 13 | EndProjectSection 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartPaster2013_UnitTests", "SmartPaster2013\SmartPaster2013_UnitTests\SmartPaster2013_UnitTests.csproj", "{B8D186B6-3465-4F1D-8157-04367BE5C9ED}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {B8D186B6-3465-4F1D-8157-04367BE5C9ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {B8D186B6-3465-4F1D-8157-04367BE5C9ED}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {B8D186B6-3465-4F1D-8157-04367BE5C9ED}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {B8D186B6-3465-4F1D-8157-04367BE5C9ED}.Release|Any CPU.Build.0 = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /SmartPaster2013/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. Project-level 3 | // suppressions either have no target or are given a specific target 4 | // and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click "In Project 8 | // Suppression File". You do not need to add suppressions to this 9 | // file manually. 10 | 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] 12 | -------------------------------------------------------------------------------- /SmartPaster2013/Guids.cs: -------------------------------------------------------------------------------- 1 | // Guids.cs 2 | // MUST match guids.h 3 | using System; 4 | 5 | namespace SmartPaster2013 6 | { 7 | static class GuidList 8 | { 9 | public const string guidSmartPaster2013PkgString = "233fade6-f9e1-4a0d-8784-089004c574fc"; 10 | public const string guidSmartPaster2013CmdSetString = "1dba502a-a6ce-4857-a13e-d9936e61ec66"; 11 | 12 | public static readonly Guid guidSmartPaster2013CmdSet = new Guid(guidSmartPaster2013CmdSetString); 13 | }; 14 | } -------------------------------------------------------------------------------- /SmartPaster2013/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/SmartPaster2013/Key.snk -------------------------------------------------------------------------------- /SmartPaster2013/PkgCmdID.cs: -------------------------------------------------------------------------------- 1 | // PkgCmdID.cs 2 | // MUST match PkgCmdID.h 3 | using System; 4 | 5 | namespace SmartPaster2013 6 | { 7 | static class PkgCmdIDList 8 | { 9 | public const uint cmdidPasteAsComment = 0x100; 10 | public const uint cmdidPasteAsString = 0x101; 11 | public const uint cmdidPasteAsVerbatimString = 0x102; 12 | public const uint cmdidPasteAsStringBuilder = 0x103; 13 | public const uint cmdidPasteAsBytes = 0x104; 14 | public const uint cmdidPasteWithReplace = 0x105; 15 | 16 | }; 17 | } -------------------------------------------------------------------------------- /SmartPaster2013/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("SmartPaster2017")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Martin Willey")] 14 | [assembly: AssemblyProduct("SmartPaster2017")] 15 | [assembly: AssemblyCopyright("")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | [assembly: ComVisible(false)] 19 | [assembly: CLSCompliant(false)] 20 | [assembly: NeutralResourcesLanguage("en-US")] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Revision and Build Numbers 30 | // by using the '*' as shown below: 31 | 32 | [assembly: AssemblyVersion("1.5.0.0")] 33 | [assembly: AssemblyFileVersion("1.5.0.0")] 34 | 35 | [assembly: InternalsVisibleTo("SmartPaster2013_IntegrationTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010027ba1044a9cff13efea75ee0f830422b00274a6f7d38ac224c0c5a2ef11ae373b6102a0a17c561292c645a2aebb9266ff3c89d30faa7757315e7702647910625157e8b5c648522d5b206b841b9d2d4ae9ea904527ddeff74b4a498181c51c635e7d76310157c327aee3dfae846720c8c161b2bc551707e4f3de7fb6f92e7f1ca")] 36 | [assembly: InternalsVisibleTo("SmartPaster2013_UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010027ba1044a9cff13efea75ee0f830422b00274a6f7d38ac224c0c5a2ef11ae373b6102a0a17c561292c645a2aebb9266ff3c89d30faa7757315e7702647910625157e8b5c648522d5b206b841b9d2d4ae9ea904527ddeff74b4a498181c51c635e7d76310157c327aee3dfae846720c8c161b2bc551707e4f3de7fb6f92e7f1ca")] 37 | -------------------------------------------------------------------------------- /SmartPaster2013/ReplaceForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace SmartPaster2013 2 | { 3 | partial class ReplaceForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.findTextBox = new System.Windows.Forms.TextBox(); 32 | this.replaceWithTextBox = new System.Windows.Forms.TextBox(); 33 | this.FindLabel = new System.Windows.Forms.Label(); 34 | this.ReplaceWithLabel = new System.Windows.Forms.Label(); 35 | this.pasteButton = new System.Windows.Forms.Button(); 36 | this.SuspendLayout(); 37 | // 38 | // findTextBox 39 | // 40 | this.findTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 41 | | System.Windows.Forms.AnchorStyles.Right))); 42 | this.findTextBox.Location = new System.Drawing.Point(82, 11); 43 | this.findTextBox.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); 44 | this.findTextBox.Name = "findTextBox"; 45 | this.findTextBox.Size = new System.Drawing.Size(345, 20); 46 | this.findTextBox.TabIndex = 0; 47 | // 48 | // replaceWithTextBox 49 | // 50 | this.replaceWithTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 51 | | System.Windows.Forms.AnchorStyles.Right))); 52 | this.replaceWithTextBox.Location = new System.Drawing.Point(82, 33); 53 | this.replaceWithTextBox.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); 54 | this.replaceWithTextBox.Name = "replaceWithTextBox"; 55 | this.replaceWithTextBox.Size = new System.Drawing.Size(345, 20); 56 | this.replaceWithTextBox.TabIndex = 1; 57 | // 58 | // FindLabel 59 | // 60 | this.FindLabel.AutoSize = true; 61 | this.FindLabel.Location = new System.Drawing.Point(9, 13); 62 | this.FindLabel.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); 63 | this.FindLabel.Name = "FindLabel"; 64 | this.FindLabel.Size = new System.Drawing.Size(30, 13); 65 | this.FindLabel.TabIndex = 2; 66 | this.FindLabel.Text = "Find:"; 67 | // 68 | // ReplaceWithLabel 69 | // 70 | this.ReplaceWithLabel.AutoSize = true; 71 | this.ReplaceWithLabel.Location = new System.Drawing.Point(9, 37); 72 | this.ReplaceWithLabel.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); 73 | this.ReplaceWithLabel.Name = "ReplaceWithLabel"; 74 | this.ReplaceWithLabel.Size = new System.Drawing.Size(72, 13); 75 | this.ReplaceWithLabel.TabIndex = 3; 76 | this.ReplaceWithLabel.Text = "Replace with:"; 77 | // 78 | // pasteButton 79 | // 80 | this.pasteButton.Location = new System.Drawing.Point(82, 57); 81 | this.pasteButton.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); 82 | this.pasteButton.Name = "pasteButton"; 83 | this.pasteButton.Size = new System.Drawing.Size(345, 19); 84 | this.pasteButton.TabIndex = 4; 85 | this.pasteButton.Text = "Paste"; 86 | this.pasteButton.UseVisualStyleBackColor = true; 87 | this.pasteButton.Click += new System.EventHandler(this.pasteButton_Click); 88 | // 89 | // ReplaceForm 90 | // 91 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 92 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 93 | this.ClientSize = new System.Drawing.Size(436, 82); 94 | this.Controls.Add(this.pasteButton); 95 | this.Controls.Add(this.ReplaceWithLabel); 96 | this.Controls.Add(this.FindLabel); 97 | this.Controls.Add(this.replaceWithTextBox); 98 | this.Controls.Add(this.findTextBox); 99 | this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); 100 | this.Name = "ReplaceForm"; 101 | this.Text = "Find/Replace in paste text"; 102 | this.ResumeLayout(false); 103 | this.PerformLayout(); 104 | 105 | } 106 | 107 | #endregion 108 | 109 | private System.Windows.Forms.TextBox findTextBox; 110 | private System.Windows.Forms.TextBox replaceWithTextBox; 111 | private System.Windows.Forms.Label FindLabel; 112 | private System.Windows.Forms.Label ReplaceWithLabel; 113 | private System.Windows.Forms.Button pasteButton; 114 | } 115 | } -------------------------------------------------------------------------------- /SmartPaster2013/ReplaceForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace SmartPaster2013 12 | { 13 | public partial class ReplaceForm : Form 14 | { 15 | public ReplaceForm() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void pasteButton_Click(object sender, EventArgs e) 21 | { 22 | this.DialogResult = DialogResult.OK; 23 | } 24 | 25 | public string TextToReplace 26 | => this.findTextBox.Text; 27 | 28 | public string ReplaceText 29 | => this.replaceWithTextBox.Text; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SmartPaster2013/ReplaceForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /SmartPaster2013/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SmartPaster2013 { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SmartPaster2013.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SmartPaster2013/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 11 | 12 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | text/microsoft-resx 119 | 120 | 121 | 2.0 122 | 123 | 124 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 125 | 126 | 127 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 128 | 129 | -------------------------------------------------------------------------------- /SmartPaster2013/Resources/Images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/SmartPaster2013/Resources/Images.png -------------------------------------------------------------------------------- /SmartPaster2013/Resources/Package.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/SmartPaster2013/Resources/Package.ico -------------------------------------------------------------------------------- /SmartPaster2013/Resources/Paste_6520.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/SmartPaster2013/Resources/Paste_6520.png -------------------------------------------------------------------------------- /SmartPaster2013/SmartFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SmartPaster2013 7 | { 8 | public static class SmartFormatter 9 | { 10 | private const string Quote = "\""; 11 | 12 | /// 13 | /// Stringinizes text passed to it for use in C# 14 | /// 15 | /// Text to be Stringinized 16 | /// C# Stringinized text 17 | public static string StringinizeInCs(string txt) 18 | { 19 | //sb to work with 20 | var sb = new StringBuilder(txt); 21 | 22 | //escape appropriately 23 | //escape the quotes with "" 24 | sb.Replace(Quote, Quote + Quote); 25 | 26 | //insert " at beginning and end 27 | sb.Insert(0, "@" + Quote); 28 | sb.Append(Quote); 29 | return sb.ToString(); 30 | } 31 | 32 | /// 33 | /// Literallies the text in C#. 34 | /// 35 | /// Literally, the text to be literallized. 36 | /// 37 | public static string LiterallyInCs(string txt) 38 | { 39 | //escape appropriately 40 | //escape the quotes with "" 41 | txt = txt.Trim() //ignore leading and trailing blank lines 42 | .Replace("\\", "\\\\") //escape backslashes 43 | .Replace(Quote, "\\\"") //escape quotes 44 | .Replace("\t", "\\t") //escape tabs 45 | .Replace("\r", "\\r") //cr 46 | .Replace("\n", "\\n") //lf 47 | //.Replace("\"\" + ", "") //"" + 48 | .Replace("\\r\\n", "\" + Environment.NewLine + \r\n\"") //escaped crlf to Env.NewLine 49 | ; 50 | 51 | return Quote + txt + Quote; 52 | } 53 | 54 | public static string LiterallyInCxx(string txt) 55 | { 56 | var lines = from line in txt.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None) 57 | select "\"" + line 58 | .Replace("\\", "\\\\") 59 | .Replace("\"", "\\\"") 60 | .Replace("\t", @"\t") 61 | + "\""; 62 | return String.Join("\r\n", lines); 63 | } 64 | 65 | /// 66 | /// Stringinizes the text in vb (VB14 verbatim). 67 | /// 68 | /// The text. 69 | /// 70 | public static string StringinizeInVb(string txt) 71 | { 72 | //double-up internal quotes 73 | txt = txt.Replace(Quote, Quote + Quote); 74 | 75 | //vb14 (vs2015+) supports verbatim strings 76 | return Quote + txt + Quote; 77 | } 78 | 79 | /// 80 | /// Literal VB (actually in C#, wat...). 81 | /// 82 | /// The text. 83 | /// 84 | public static string LiterallyInVb(string txt) 85 | { 86 | //double-up internal quotes 87 | txt = txt.Replace(Quote, Quote + Quote); 88 | txt = txt.Trim() //ignore leading and trailing blank lines 89 | .Replace(Quote, Quote + Quote) //escape quotes 90 | .Replace("\t", "\" & vbTab & \"") //explicit Tabs 91 | .Replace("\r", "\" & vbCr & \"") //cr 92 | .Replace("\n", "\" & vbLf & \"") //lf 93 | .Replace("\" & vbCr & \"\" & vbLf & \"", "\" & vbCrLf & _\r\n\"") //escaped cr + lf to CrLf + vb line continuation 94 | .Replace("\"\" & ", ""); //"" & 95 | 96 | return Quote + txt + Quote; 97 | } 98 | 99 | public static string CDataizeInVb(string txt) 100 | { 101 | const string cdataStart = ".Value"; 104 | var sb = new StringBuilder(); 105 | 106 | sb.AppendLine(cdataStart); 107 | sb.AppendLine(txt); 108 | sb.AppendLine(cdataEnd); 109 | 110 | //add the dec statement 111 | sb.Insert(0, "Dim s As String = " + Environment.NewLine); 112 | 113 | //and return 114 | return sb.ToString(); 115 | } 116 | 117 | /// 118 | /// Commentizes text passed to it for use in C# 119 | /// 120 | /// Text to be Stringinized 121 | /// C# Commentized text 122 | public static string CommentizeInCs(string txt) 123 | { 124 | const string cmtChar = "//"; 125 | 126 | var sb = new StringBuilder(txt.Length); 127 | 128 | //process the passed string (txt), one line at a time 129 | //the original was horrible WTF code 130 | using (var reader = new StringReader(txt)) 131 | { 132 | string line; 133 | while ((line = reader.ReadLine()) != null) 134 | { 135 | sb.AppendLine(cmtChar + line); 136 | } 137 | } 138 | 139 | return sb.ToString(); 140 | } 141 | 142 | public static string CommentizeInVb(string txt) 143 | { 144 | const string cmtChar = "'"; 145 | 146 | var sb = new StringBuilder(txt.Length); 147 | 148 | //process the passed string (txt), one line at a time 149 | using (var reader = new StringReader(txt)) 150 | { 151 | string line; 152 | while ((line = reader.ReadLine()) != null) 153 | { 154 | sb.AppendLine(cmtChar + line); 155 | } 156 | } 157 | 158 | return sb.ToString(); 159 | } 160 | 161 | public static string CommentizeInXml(string txt) 162 | { 163 | //we don't need to escape < or >, just -- 164 | return string.Concat(""); 165 | } 166 | 167 | public static string StringbuilderizeInCs(string txt, string sbName) 168 | { 169 | //sb to work with 170 | var sb = new StringBuilder(txt); 171 | 172 | //escape \,", and {} 173 | sb.Replace(Quote, Quote + Quote); 174 | 175 | //process the passed string (txt), one line at a time 176 | 177 | //dump the stringbuilder into a temp string 178 | string fullString = sb.ToString(); 179 | sb.Clear(); //lovely .net 4 - sb.Remove(0, sb.Length); 180 | 181 | //the original was horrible 182 | using (var reader = new StringReader(fullString)) 183 | { 184 | string line; 185 | while ((line = reader.ReadLine()) != null) 186 | { 187 | sb.Append(sbName + ".AppendLine("); 188 | sb.Append("@" + Quote); 189 | sb.Append(line); 190 | sb.AppendLine(Quote + ");"); 191 | } 192 | } 193 | 194 | //TODO: Better '@"" + ' replacement to not cover inside strings 195 | sb.Replace("@" + Quote + Quote + " + ", ""); 196 | 197 | //add the dec statement 198 | sb.Insert(0, "var " + sbName + " = new System.Text.StringBuilder(" + txt.Length + ");" + Environment.NewLine); 199 | 200 | //and return 201 | return sb.ToString(); 202 | } 203 | 204 | public static string StringbuilderizeInVb(string txt, string sbName) 205 | { 206 | //sb to work with 207 | var sb = new StringBuilder(txt); 208 | 209 | //escape 210 | sb.Replace(Quote, Quote + Quote); 211 | 212 | //dump the stringbuilder into a temp string 213 | var fullString = sb.ToString(); 214 | sb.Clear(); 215 | 216 | //read it line by line 217 | using (var reader = new StringReader(fullString)) 218 | { 219 | string line; 220 | while ((line = reader.ReadLine()) != null) 221 | { 222 | sb.Append(sbName + ".AppendLine("); 223 | sb.Append(Quote); 224 | sb.Append(line); 225 | sb.Append(Quote); 226 | sb.AppendLine(")"); 227 | } 228 | } 229 | 230 | //add the dec statement 231 | sb.Insert(0, "Dim " + sbName + " As New System.Text.StringBuilder(" + txt.Length + ")" + Environment.NewLine); 232 | 233 | //and return 234 | return sb.ToString(); 235 | } 236 | 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; //clipboard 3 | using EnvDTE; 4 | using EnvDTE80; 5 | using System.Text; 6 | 7 | namespace SmartPaster2013 8 | { 9 | /// 10 | /// Class responsible for doing the pasting/manipulating of clipdata. 11 | /// 12 | internal sealed class SmartPaster 13 | { 14 | /// 15 | /// Convient property to retrieve the clipboard text from the clipboard 16 | /// 17 | private static string ClipboardText 18 | { 19 | get 20 | { 21 | IDataObject iData = Clipboard.GetDataObject(); 22 | if (iData == null) return string.Empty; 23 | //is it Unicode? Then we use that 24 | if (iData.GetDataPresent(DataFormats.UnicodeText)) 25 | return Convert.ToString(iData.GetData(DataFormats.UnicodeText)); 26 | //otherwise ANSI 27 | if (iData.GetDataPresent(DataFormats.Text)) 28 | return Convert.ToString(iData.GetData(DataFormats.Text)); 29 | return string.Empty; 30 | } 31 | } 32 | 33 | 34 | /// 35 | /// Inserts text at current cursor location in the application 36 | /// 37 | /// application with activewindow 38 | /// text to insert 39 | private static void Paste(DTE2 application, string text) 40 | { 41 | //get the text document 42 | var txt = (TextDocument)application.ActiveDocument.Object("TextDocument"); 43 | 44 | //get an edit point 45 | EditPoint ep = txt.Selection.ActivePoint.CreateEditPoint(); 46 | 47 | //get a start point 48 | EditPoint sp = txt.Selection.ActivePoint.CreateEditPoint(); 49 | 50 | //open the undo context 51 | bool isOpen = application.UndoContext.IsOpen; 52 | if (!isOpen) 53 | application.UndoContext.Open("SmartPaster"); 54 | 55 | //clear the selection 56 | if (!txt.Selection.IsEmpty) 57 | txt.Selection.Delete(); 58 | 59 | //insert the text 60 | //ep.Insert(Indent(text, ep.LineCharOffset)) 61 | ep.Insert(text); 62 | 63 | //smart format 64 | sp.SmartFormat(ep); 65 | 66 | //close the context 67 | if (!isOpen) 68 | application.UndoContext.Close(); 69 | } 70 | 71 | private static bool IsXml(DTE2 application) 72 | { 73 | var caption = application.ActiveWindow.Caption; 74 | foreach (var ext in new [] { ".xml", ".xsd", ".config", ".xaml"}) 75 | { 76 | if (caption.EndsWith(ext, StringComparison.OrdinalIgnoreCase)) 77 | return true; 78 | } 79 | return false; 80 | } 81 | private static bool IsVb(DTE2 application) 82 | { 83 | return application.ActiveWindow.Caption.EndsWith(".vb", StringComparison.OrdinalIgnoreCase); 84 | } 85 | private static bool IsCs(DTE2 application) 86 | { 87 | return application.ActiveWindow.Caption.EndsWith(".cs", StringComparison.OrdinalIgnoreCase); 88 | } 89 | 90 | private static bool IsCxx(DTE2 application) 91 | { 92 | return application.ActiveDocument.Language == "C/C++"; 93 | } 94 | #region "Paste As ..." 95 | 96 | /// 97 | /// Public method to paste and format clipboard text as string the cursor 98 | /// location for the configured or active window's langage . 99 | /// 100 | /// application to insert 101 | public void PasteAsString(DTE2 application) 102 | { 103 | string text; 104 | if (IsVb(application)) 105 | text = SmartFormatter.LiterallyInVb(ClipboardText); 106 | else if (IsCs(application)) 107 | text = SmartFormatter.LiterallyInCs(ClipboardText); 108 | else if (IsCxx(application)) 109 | text = SmartFormatter.LiterallyInCxx(ClipboardText); 110 | else 111 | text = ClipboardText; 112 | Paste(application, text); 113 | } 114 | 115 | public void PasteAsBytes(DTE2 application) 116 | { 117 | if (IsCxx(application) || IsCs(application)) 118 | { 119 | var sb = new StringBuilder(); 120 | var count = 0; 121 | foreach (var ch in ClipboardText) 122 | { 123 | sb.AppendFormat("0x{0:x2}, ", (int)ch); 124 | if (++count == 16) 125 | { 126 | count = 0; 127 | sb.AppendLine(); 128 | } 129 | } 130 | Paste(application, sb.ToString()); 131 | } 132 | } 133 | 134 | /// 135 | /// Pastes as verbatim string. 136 | /// 137 | /// The application. 138 | public void PasteAsVerbatimString(DTE2 application) 139 | { 140 | if (IsVb(application)) 141 | { 142 | //vb14 has verbatim strings, otherwise do the CData trick 143 | int version; 144 | var appVersion = application.Version; 145 | var p = appVersion.IndexOf('.'); //12.0 in VS2013, but MSDN says dp is optional 146 | if (p > 0) appVersion = appVersion.Substring(0, p); 147 | 148 | int.TryParse(appVersion, out version); 149 | 150 | Paste(application, 151 | version < 14 152 | ? SmartFormatter.CDataizeInVb(ClipboardText) 153 | : SmartFormatter.StringinizeInVb(ClipboardText)); 154 | return; 155 | } 156 | //c# 157 | Paste(application, SmartFormatter.StringinizeInCs(ClipboardText)); 158 | } 159 | 160 | 161 | /// 162 | /// Public method to paste and format clipboard text as comment the cursor 163 | /// location for the configured or active window's langage . 164 | /// 165 | /// application to insert 166 | public void PasteAsComment(DTE2 application) 167 | { 168 | string text; 169 | if (IsVb(application)) 170 | { 171 | text = SmartFormatter.CommentizeInVb(ClipboardText); 172 | } 173 | else if (IsXml(application)) 174 | { 175 | text = SmartFormatter.CommentizeInXml(ClipboardText); 176 | } 177 | else 178 | { 179 | text = SmartFormatter.CommentizeInCs(ClipboardText); 180 | } 181 | Paste(application, text); 182 | } 183 | 184 | 185 | /// 186 | /// Public method to paste format clipboard text into a specified region 187 | /// 188 | /// application to insert 189 | public void PasteAsRegion(DTE2 application) 190 | { 191 | //get the region name 192 | const string region = "myRegion"; 193 | 194 | //it's so simple, we really don't need a function 195 | string csRegionized = "#region " + region + Environment.NewLine + ClipboardText + Environment.NewLine + "#endregion"; 196 | 197 | //and paste 198 | Paste(application, csRegionized); 199 | } 200 | 201 | /// 202 | /// Public method to paste and format clipboard text as stringbuilder the cursor 203 | /// location for the configured or active window's langage . 204 | /// 205 | /// application to insert 206 | public void PasteAsStringBuilder(DTE2 application) 207 | { 208 | const string stringbuilder = "sb"; 209 | Paste(application, IsVb(application) ? 210 | SmartFormatter.StringbuilderizeInVb(ClipboardText, stringbuilder) : 211 | SmartFormatter.StringbuilderizeInCs(ClipboardText, stringbuilder)); 212 | } 213 | 214 | public void PasteWithReplace(DTE2 application) 215 | { 216 | using (var replaceForm = new ReplaceForm()) 217 | { 218 | if (replaceForm.ShowDialog() == DialogResult.OK) 219 | { 220 | var src = replaceForm.TextToReplace; 221 | var dst = replaceForm.ReplaceText; 222 | var txt = ClipboardText.Replace(src, dst); 223 | Paste(application, txt); 224 | } 225 | } 226 | } 227 | 228 | #endregion 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 15.0 6 | 12.0 7 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 8 | 9 | 10 | 11 | 12 | 12.0 13 | publish\ 14 | true 15 | Disk 16 | false 17 | Foreground 18 | 7 19 | Days 20 | false 21 | false 22 | true 23 | 0 24 | 1.0.0.%2a 25 | false 26 | false 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | Debug 35 | AnyCPU 36 | 2.0 37 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2} 38 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 39 | Library 40 | Properties 41 | SmartPaster2013 42 | SmartPaster2019 43 | True 44 | Key.snk 45 | v4.6 46 | 47 | 48 | true 49 | full 50 | false 51 | bin\Debug\ 52 | DEBUG;TRACE 53 | prompt 54 | 4 55 | True 56 | 57 | 58 | pdbonly 59 | true 60 | bin\Release\ 61 | TRACE 62 | prompt 63 | 4 64 | true 65 | 66 | 67 | 68 | False 69 | False 70 | 71 | 72 | False 73 | False 74 | 75 | 76 | False 77 | False 78 | 79 | 80 | False 81 | False 82 | 83 | 84 | ..\packages\Microsoft.VisualStudio.CoreUtility.15.0.26201\lib\net45\Microsoft.VisualStudio.CoreUtility.dll 85 | True 86 | 87 | 88 | ..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll 89 | True 90 | 91 | 92 | ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll 93 | True 94 | 95 | 96 | ..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll 97 | True 98 | 99 | 100 | ..\packages\Microsoft.VisualStudio.Shell.Framework.15.0.26201\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll 101 | True 102 | 103 | 104 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll 105 | True 106 | 107 | 108 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll 109 | True 110 | 111 | 112 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll 113 | True 114 | 115 | 116 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll 117 | True 118 | 119 | 120 | ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll 121 | True 122 | 123 | 124 | ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll 125 | True 126 | 127 | 128 | ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll 129 | True 130 | 131 | 132 | ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll 133 | True 134 | 135 | 136 | ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll 137 | True 138 | 139 | 140 | ..\packages\Microsoft.VisualStudio.Threading.14.1.111\lib\net45\Microsoft.VisualStudio.Threading.dll 141 | True 142 | 143 | 144 | ..\packages\Microsoft.VisualStudio.Utilities.15.0.26201\lib\net45\Microsoft.VisualStudio.Utilities.dll 145 | True 146 | 147 | 148 | ..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll 149 | True 150 | 151 | 152 | False 153 | False 154 | 155 | 156 | False 157 | False 158 | 159 | 160 | 161 | 162 | true 163 | 164 | 165 | true 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | Form 179 | 180 | 181 | ReplaceForm.cs 182 | 183 | 184 | True 185 | True 186 | Resources.resx 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | ReplaceForm.cs 198 | 199 | 200 | ResXFileCodeGenerator 201 | Resources.Designer.cs 202 | Designer 203 | 204 | 205 | true 206 | VSPackage 207 | 208 | 209 | 210 | 211 | 212 | 213 | Designer 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | Menus.ctmenu 222 | Designer 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | License.txt 231 | true 232 | 233 | 234 | Always 235 | true 236 | 237 | 238 | 239 | 240 | 241 | False 242 | .NET Framework 3.5 SP1 243 | false 244 | 245 | 246 | 247 | true 248 | 249 | 250 | 251 | 252 | 259 | 260 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013.vsct: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 41 | 42 | 43 | 44 | 45 | 46 | Paste As... 47 | Paste As... 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 | 72 | 79 | 80 | 87 | 94 | 101 | 108 | 115 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013Package.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Runtime.InteropServices; 5 | using System.ComponentModel.Design; 6 | using Microsoft.VisualStudio.Shell; 7 | using EnvDTE; 8 | using EnvDTE80; 9 | 10 | namespace SmartPaster2013 11 | { 12 | /// 13 | /// This is the class that implements the package exposed by this assembly. 14 | /// 15 | /// The minimum requirement for a class to be considered a valid package for Visual Studio 16 | /// is to implement the IVsPackage interface and register itself with the shell. 17 | /// This package uses the helper classes defined inside the Managed Package Framework (MPF) 18 | /// to do it: it derives from the Package class that provides the implementation of the 19 | /// IVsPackage interface and uses the registration attributes defined in the framework to 20 | /// register itself and its components with the shell. 21 | /// 22 | // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is 23 | // a package. 24 | [PackageRegistration(UseManagedResourcesOnly = true)] 25 | // This attribute is used to register the information needed to show this package 26 | // in the Help/About dialog of Visual Studio. 27 | [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] 28 | // This attribute is needed to let the shell know that this package exposes some menus. 29 | [ProvideMenuResource("Menus.ctmenu", 1)] 30 | [Guid(GuidList.guidSmartPaster2013PkgString)] 31 | public sealed class SmartPaster2013Package : Package 32 | { 33 | /// 34 | /// Default constructor of the package. 35 | /// Inside this method you can place any initialization code that does not require 36 | /// any Visual Studio service because at this point the package object is created but 37 | /// not sited yet inside Visual Studio environment. The place to do all the other 38 | /// initialization is the Initialize method. 39 | /// 40 | public SmartPaster2013Package() 41 | { 42 | Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString())); 43 | // Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString())); 44 | } 45 | 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // Overridden Package Implementation 50 | #region Package Members 51 | 52 | /// 53 | /// Initialization of the package; this method is called right after the package is sited, so this is the place 54 | /// where you can put all the initialization code that rely on services provided by VisualStudio. 55 | /// 56 | protected override void Initialize() 57 | { 58 | Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString())); 59 | base.Initialize(); 60 | 61 | 62 | // Add our command handlers for menu (commands must exist in the .vsct file) 63 | var mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 64 | if (null != mcs) 65 | { 66 | // Create the command for the menu item. 67 | var menuCommandVerbatimID = new CommandID(GuidList.guidSmartPaster2013CmdSet, (int)PkgCmdIDList.cmdidPasteAsVerbatimString); 68 | var menuItemVerbatim = new MenuCommand(CallPasteAsVerbatimString, menuCommandVerbatimID); 69 | mcs.AddCommand(menuItemVerbatim); 70 | 71 | var menuCommandStringID = new CommandID(GuidList.guidSmartPaster2013CmdSet, (int)PkgCmdIDList.cmdidPasteAsString); 72 | var menuItemString = new MenuCommand(CallPasteAsString, menuCommandStringID); 73 | mcs.AddCommand(menuItemString); 74 | 75 | var menuCommandBytesID = new CommandID(GuidList.guidSmartPaster2013CmdSet, (int)PkgCmdIDList.cmdidPasteAsBytes); 76 | var menuItemBytes = new MenuCommand(CallPasteAsBytes, menuCommandBytesID); 77 | mcs.AddCommand(menuItemBytes); 78 | 79 | var menuCommandSbID = new CommandID(GuidList.guidSmartPaster2013CmdSet, (int)PkgCmdIDList.cmdidPasteAsStringBuilder); 80 | var menuItemSb = new MenuCommand(CallPasteAsStringBuilder, menuCommandSbID); 81 | mcs.AddCommand(menuItemSb); 82 | 83 | var menuCommandID = new CommandID(GuidList.guidSmartPaster2013CmdSet, (int)PkgCmdIDList.cmdidPasteAsComment); 84 | var menuItem = new MenuCommand(CallPasteAsComment, menuCommandID); 85 | mcs.AddCommand(menuItem); 86 | 87 | var menuCommandReplaceID = new CommandID(GuidList.guidSmartPaster2013CmdSet, (int)PkgCmdIDList.cmdidPasteWithReplace); 88 | var menuItemReplace = new MenuCommand(CallPasteWithReplace, menuCommandReplaceID); 89 | mcs.AddCommand(menuItemReplace); 90 | 91 | } 92 | } 93 | #endregion 94 | 95 | 96 | 97 | /// 98 | /// This function is the callback used to execute a command when the a menu item is clicked. 99 | /// See the Initialize method to see how the menu item is associated to this function using 100 | /// the OleMenuCommandService service and the MenuCommand class. 101 | /// 102 | private void CallPasteAsComment(object sender, EventArgs e) 103 | { 104 | var dte = (DTE2)GetService(typeof(DTE)); 105 | var sp = new SmartPaster(); 106 | sp.PasteAsComment(dte); 107 | } 108 | 109 | private void CallPasteAsStringBuilder(object sender, EventArgs e) 110 | { 111 | var dte = (DTE2)GetService(typeof(DTE)); 112 | var sp = new SmartPaster(); 113 | sp.PasteAsStringBuilder(dte); 114 | } 115 | 116 | private void CallPasteAsString(object sender, EventArgs e) 117 | { 118 | var dte = (DTE2)GetService(typeof(DTE)); 119 | var sp = new SmartPaster(); 120 | sp.PasteAsString(dte); 121 | } 122 | 123 | private void CallPasteAsBytes(object sender, EventArgs e) 124 | { 125 | var dte = (DTE2)GetService(typeof(DTE)); 126 | var sp = new SmartPaster(); 127 | sp.PasteAsBytes(dte); 128 | } 129 | 130 | private void CallPasteAsVerbatimString(object sender, EventArgs e) 131 | { 132 | var dte = (DTE2)GetService(typeof(DTE)); 133 | var sp = new SmartPaster(); 134 | sp.PasteAsVerbatimString(dte); 135 | } 136 | 137 | private void CallPasteWithReplace(object sender, EventArgs e) 138 | { 139 | var dte = (DTE2)GetService(typeof(DTE)); 140 | var sp = new SmartPaster(); 141 | sp.PasteWithReplace(dte); 142 | } 143 | 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Microsoft.VsSDK.IntegrationTestLibrary 3 | { 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Runtime.InteropServices; 8 | using System.Threading; 9 | using Microsoft.VisualStudio.Shell.Interop; 10 | using Microsoft.VisualStudio.Shell; 11 | 12 | /// 13 | /// This class is responsible to close dialog boxes that pop up during different VS Calls 14 | /// 15 | internal class DialogBoxPurger : IDisposable 16 | { 17 | /// 18 | /// The default number of milliseconds to wait for the threads to signal to terminate. 19 | /// 20 | private const int DefaultMillisecondsToWait = 3500; 21 | 22 | /// 23 | /// Object used for synchronization between thread calls. 24 | /// 25 | internal static volatile object Mutex = new object(); 26 | 27 | /// 28 | /// The IVsUIShell. This cannot be queried on the working thread from the service provider. Must be done in the main thread.!! 29 | /// 30 | private IVsUIShell uiShell; 31 | 32 | /// 33 | /// The button to "press" on the dialog. 34 | /// 35 | private int buttonAction; 36 | 37 | /// 38 | /// Thread signales to the calling thread that it is done. 39 | /// 40 | private bool exitThread = false; 41 | 42 | /// 43 | /// Calling thread signales to this thread to die. 44 | /// 45 | private AutoResetEvent threadDone = new AutoResetEvent(false); 46 | 47 | /// 48 | /// The queued thread started. 49 | /// 50 | private AutoResetEvent threadStarted = new AutoResetEvent(false); 51 | 52 | /// 53 | /// The result of the dialogbox closing for all the dialog boxes. That is if there are two of them and one fails this will be false. 54 | /// 55 | private bool dialogBoxCloseResult = false; 56 | 57 | /// 58 | /// The expected text to see on the dialog box. If set the thread will continue finding the dialog box with this text. 59 | /// 60 | private string expectedDialogBoxText = String.Empty; 61 | 62 | /// 63 | /// The number of the same dialog boxes to wait for. 64 | /// This is for scenarios when two dialog boxes with the same text are popping up. 65 | /// 66 | private int numberOfDialogsToWaitFor = 1; 67 | 68 | /// 69 | /// Has the object been disposed. 70 | /// 71 | private bool isDisposed; 72 | 73 | /// 74 | /// Overloaded ctor. 75 | /// 76 | /// The botton to "press" on the dialog box. 77 | /// The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes 78 | /// The expected dialog box message to check for. 79 | internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor, string expectedDialogMesssage) 80 | { 81 | this.buttonAction = buttonAction; 82 | this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor; 83 | this.expectedDialogBoxText = expectedDialogMesssage; 84 | } 85 | 86 | /// 87 | /// Overloaded ctor. 88 | /// 89 | /// The botton to "press" on the dialog box. 90 | /// The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes 91 | internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor) 92 | { 93 | this.buttonAction = buttonAction; 94 | this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor; 95 | } 96 | 97 | /// 98 | /// Overloaded ctor. 99 | /// 100 | /// The botton to "press" on the dialog box. 101 | /// The expected dialog box message to check for. 102 | internal DialogBoxPurger(int buttonAction, string expectedDialogMesssage) 103 | { 104 | this.buttonAction = buttonAction; 105 | this.expectedDialogBoxText = expectedDialogMesssage; 106 | } 107 | 108 | /// 109 | /// Overloaded ctor. 110 | /// 111 | /// The botton to "press" on the dialog box. 112 | internal DialogBoxPurger(int buttonAction) 113 | { 114 | this.buttonAction = buttonAction; 115 | } 116 | 117 | /// 118 | #region IDisposable Members 119 | 120 | void IDisposable.Dispose() 121 | { 122 | if (this.isDisposed) 123 | { 124 | return; 125 | } 126 | 127 | this.WaitForDialogThreadToTerminate(); 128 | 129 | this.isDisposed = true; 130 | } 131 | 132 | /// 133 | /// Spawns a thread that will start listening to dialog boxes. 134 | /// 135 | internal void Start() 136 | { 137 | // We ask for the uishell here since we cannot do that on the therad that we will spawn. 138 | IVsUIShell uiShell = Package.GetGlobalService(typeof(SVsUIShell)) as IVsUIShell; 139 | 140 | if (uiShell == null) 141 | { 142 | throw new InvalidOperationException("Could not get the uiShell from the serviceProvider"); 143 | } 144 | 145 | this.uiShell = uiShell; 146 | 147 | System.Threading.Thread thread = new System.Threading.Thread(new ThreadStart(this.HandleDialogBoxes)); 148 | thread.Start(); 149 | 150 | // We should never deadlock here, hence do not use the lock. Wait to be sure that the thread started. 151 | this.threadStarted.WaitOne(3500, false); 152 | } 153 | 154 | /// 155 | /// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down, 156 | /// then it will tell to the thread to do it. 157 | /// 158 | internal bool WaitForDialogThreadToTerminate() 159 | { 160 | return this.WaitForDialogThreadToTerminate(DefaultMillisecondsToWait); 161 | } 162 | 163 | /// 164 | /// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down, 165 | /// then it will tell to the thread to do it. 166 | /// 167 | /// The number milliseconds to wait for until the dialog purger thread is signaled to terminate. This is just for safe precaution that we do not hang. 168 | /// The result of the dialog boxes closing 169 | internal bool WaitForDialogThreadToTerminate(int numberOfMillisecondsToWait) 170 | { 171 | bool signaled = false; 172 | 173 | // We give millisecondsToWait sec to bring up and close the dialog box. 174 | signaled = this.threadDone.WaitOne(numberOfMillisecondsToWait, false); 175 | 176 | // Kill the thread since a timeout occured. 177 | if (!signaled) 178 | { 179 | lock (Mutex) 180 | { 181 | // Set the exit thread to true. Next time the thread will kill itselfes if it sees 182 | this.exitThread = true; 183 | } 184 | 185 | // Wait for the thread to finish. We should never deadlock here. 186 | this.threadDone.WaitOne(); 187 | } 188 | 189 | return this.dialogBoxCloseResult; 190 | } 191 | 192 | /// 193 | /// This is the thread method. 194 | /// 195 | private void HandleDialogBoxes() 196 | { 197 | // No synchronization numberOfDialogsToWaitFor since it is readonly 198 | IntPtr[] hwnds = new IntPtr[this.numberOfDialogsToWaitFor]; 199 | bool[] dialogBoxCloseResults = new bool[this.numberOfDialogsToWaitFor]; 200 | 201 | try 202 | { 203 | // Signal that we started 204 | lock (Mutex) 205 | { 206 | this.threadStarted.Set(); 207 | } 208 | 209 | // The loop will be exited either if a message is send by the caller thread or if we found the dialog. If a message box text is specified the loop will not exit until the dialog is found. 210 | bool stayInLoop = true; 211 | int dialogBoxesToWaitFor = 1; 212 | 213 | while (stayInLoop) 214 | { 215 | int hwndIndex = dialogBoxesToWaitFor - 1; 216 | 217 | // We need to lock since the caller might set context to null. 218 | lock (Mutex) 219 | { 220 | if (this.exitThread) 221 | { 222 | break; 223 | } 224 | 225 | // We protect the shell too from reentrency. 226 | this.uiShell.GetDialogOwnerHwnd(out hwnds[hwndIndex]); 227 | 228 | } 229 | 230 | if (hwnds[hwndIndex] != IntPtr.Zero) 231 | { 232 | StringBuilder windowClassName = new StringBuilder(256); 233 | NativeMethods.GetClassName(hwnds[hwndIndex], windowClassName, windowClassName.Capacity); 234 | 235 | // The #32770 is the class name of a messagebox dialog. 236 | if (windowClassName.ToString().Contains("#32770")) 237 | { 238 | IntPtr unmanagedMemoryLocation = IntPtr.Zero; 239 | string dialogBoxText = String.Empty; 240 | try 241 | { 242 | unmanagedMemoryLocation = Marshal.AllocHGlobal(10 * 1024); 243 | NativeMethods.EnumChildWindows(hwnds[hwndIndex], new NativeMethods.CallBack(FindMessageBoxString), unmanagedMemoryLocation); 244 | dialogBoxText = Marshal.PtrToStringUni(unmanagedMemoryLocation); 245 | } 246 | finally 247 | { 248 | if (unmanagedMemoryLocation != IntPtr.Zero) 249 | { 250 | Marshal.FreeHGlobal(unmanagedMemoryLocation); 251 | } 252 | } 253 | 254 | lock (Mutex) 255 | { 256 | 257 | // Since this is running on the main thread be sure that we close the dialog. 258 | bool dialogCloseResult = false; 259 | if (this.buttonAction != 0) 260 | { 261 | dialogCloseResult = NativeMethods.EndDialog(hwnds[hwndIndex], this.buttonAction); 262 | } 263 | 264 | // Check if we have found the right dialog box. 265 | if (String.IsNullOrEmpty(this.expectedDialogBoxText) || (!String.IsNullOrEmpty(dialogBoxText) && String.Compare(this.expectedDialogBoxText, dialogBoxText.Trim(), StringComparison.OrdinalIgnoreCase) == 0)) 266 | { 267 | dialogBoxCloseResults[hwndIndex] = dialogCloseResult; 268 | if (dialogBoxesToWaitFor++ >= this.numberOfDialogsToWaitFor) 269 | { 270 | stayInLoop = false; 271 | } 272 | } 273 | } 274 | } 275 | } 276 | } 277 | } 278 | finally 279 | { 280 | //Let the main thread run a possible close command. 281 | System.Threading.Thread.Sleep(2000); 282 | 283 | foreach (IntPtr hwnd in hwnds) 284 | { 285 | // At this point the dialog should be closed, if not attempt to close it. 286 | if (hwnd != IntPtr.Zero) 287 | { 288 | NativeMethods.SendMessage(hwnd, NativeMethods.WM_CLOSE, 0, new IntPtr(0)); 289 | } 290 | } 291 | 292 | lock (Mutex) 293 | { 294 | // Be optimistic. 295 | this.dialogBoxCloseResult = true; 296 | 297 | for (int i = 0; i < dialogBoxCloseResults.Length; i++) 298 | { 299 | if (!dialogBoxCloseResults[i]) 300 | { 301 | this.dialogBoxCloseResult = false; 302 | break; 303 | } 304 | } 305 | 306 | this.threadDone.Set(); 307 | } 308 | } 309 | } 310 | 311 | /// 312 | /// Finds a messagebox string on a messagebox. 313 | /// 314 | /// The windows handle of the dialog 315 | /// A pointer to the memorylocation the string will be written to 316 | /// True if found. 317 | private static bool FindMessageBoxString(IntPtr hwnd, IntPtr unmanagedMemoryLocation) 318 | { 319 | StringBuilder sb = new StringBuilder(512); 320 | NativeMethods.GetClassName(hwnd, sb, sb.Capacity); 321 | 322 | if (sb.ToString().ToLower().Contains("static")) 323 | { 324 | StringBuilder windowText = new StringBuilder(2048); 325 | NativeMethods.GetWindowText(hwnd, windowText, windowText.Capacity); 326 | 327 | if (windowText.Length > 0) 328 | { 329 | IntPtr stringAsPtr = IntPtr.Zero; 330 | try 331 | { 332 | stringAsPtr = Marshal.StringToHGlobalAnsi(windowText.ToString()); 333 | char[] stringAsArray = windowText.ToString().ToCharArray(); 334 | 335 | // Since unicode characters are copied check if we are out of the allocated length. 336 | // If not add the end terminating zero. 337 | if ((2 * stringAsArray.Length) + 1 < 2048) 338 | { 339 | Marshal.Copy(stringAsArray, 0, unmanagedMemoryLocation, stringAsArray.Length); 340 | Marshal.WriteInt32(unmanagedMemoryLocation, 2 * stringAsArray.Length, 0); 341 | } 342 | } 343 | finally 344 | { 345 | if (stringAsPtr != IntPtr.Zero) 346 | { 347 | Marshal.FreeHGlobal(stringAsPtr); 348 | } 349 | } 350 | return false; 351 | } 352 | } 353 | 354 | return true; 355 | } 356 | 357 | #endregion 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/IntegrationTest Library/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | This code is licensed under the Visual Studio SDK license terms. 5 | THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | 10 | ***************************************************************************/ 11 | 12 | namespace Microsoft.VsSDK.IntegrationTestLibrary 13 | { 14 | using System; 15 | using System.Collections.Generic; 16 | using System.Text; 17 | using System.Runtime.InteropServices; 18 | using System.Threading; 19 | using Microsoft.VisualStudio.Shell.Interop; 20 | 21 | /// 22 | /// Defines pinvoked utility methods and internal VS Constants 23 | /// 24 | internal static class NativeMethods 25 | { 26 | internal delegate bool CallBack(IntPtr hwnd, IntPtr lParam); 27 | 28 | // Declare two overloaded SendMessage functions 29 | [DllImport("user32.dll")] 30 | internal static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg, 31 | UInt32 wParam, IntPtr lParam); 32 | 33 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 34 | internal static extern bool PeekMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove); 35 | 36 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 37 | internal static extern bool TranslateMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg); 38 | 39 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 40 | internal static extern int DispatchMessage([In] ref Microsoft.VisualStudio.OLE.Interop.MSG msg); 41 | 42 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 43 | internal static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach); 44 | 45 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 46 | internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); 47 | 48 | [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 49 | internal static extern uint GetCurrentThreadId(); 50 | 51 | [DllImport("user32")] 52 | internal static extern int EnumChildWindows(IntPtr hwnd, CallBack x, IntPtr y); 53 | 54 | [DllImport("user32")] 55 | internal static extern bool IsWindowVisible(IntPtr hDlg); 56 | 57 | [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 58 | internal static extern IntPtr SetFocus(IntPtr hWnd); 59 | 60 | [DllImport("user32")] 61 | internal static extern int GetClassName(IntPtr hWnd, 62 | StringBuilder className, 63 | int stringLength); 64 | [DllImport("user32")] 65 | internal static extern int GetWindowText(IntPtr hWnd, StringBuilder className, int stringLength); 66 | 67 | 68 | [DllImport("user32")] 69 | internal static extern bool EndDialog(IntPtr hDlg, int result); 70 | 71 | [DllImport("Kernel32")] 72 | internal static extern long GetLastError(); 73 | 74 | internal const int QS_KEY = 0x0001, 75 | QS_MOUSEMOVE = 0x0002, 76 | QS_MOUSEBUTTON = 0x0004, 77 | QS_POSTMESSAGE = 0x0008, 78 | QS_TIMER = 0x0010, 79 | QS_PAINT = 0x0020, 80 | QS_SENDMESSAGE = 0x0040, 81 | QS_HOTKEY = 0x0080, 82 | QS_ALLPOSTMESSAGE = 0x0100, 83 | QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON, 84 | QS_INPUT = QS_MOUSE | QS_KEY, 85 | QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY, 86 | QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE; 87 | 88 | internal const int Facility_Win32 = 7; 89 | 90 | internal const int WM_CLOSE = 0x0010; 91 | 92 | internal const int 93 | S_FALSE = 0x00000001, 94 | S_OK = 0x00000000, 95 | 96 | IDOK = 1, 97 | IDCANCEL = 2, 98 | IDABORT = 3, 99 | IDRETRY = 4, 100 | IDIGNORE = 5, 101 | IDYES = 6, 102 | IDNO = 7, 103 | IDCLOSE = 8, 104 | IDHELP = 9, 105 | IDTRYAGAIN = 10, 106 | IDCONTINUE = 11; 107 | 108 | internal static long HResultFromWin32(long error) 109 | { 110 | if (error <= 0) 111 | { 112 | return error; 113 | } 114 | 115 | return ((error & 0x0000FFFF) | (Facility_Win32 << 16) | 0x80000000); 116 | } 117 | 118 | /// 119 | /// Please use this "approved" method to compare file names. 120 | /// 121 | public static bool IsSamePath(string file1, string file2) 122 | { 123 | if (file1 == null || file1.Length == 0) 124 | { 125 | return (file2 == null || file2.Length == 0); 126 | } 127 | 128 | Uri uri1 = null; 129 | Uri uri2 = null; 130 | 131 | try 132 | { 133 | if (!Uri.TryCreate(file1, UriKind.Absolute, out uri1) || !Uri.TryCreate(file2, UriKind.Absolute, out uri2)) 134 | { 135 | return false; 136 | } 137 | 138 | if (uri1 != null && uri1.IsFile && uri2 != null && uri2.IsFile) 139 | { 140 | return 0 == String.Compare(uri1.LocalPath, uri2.LocalPath, StringComparison.OrdinalIgnoreCase); 141 | } 142 | 143 | return file1 == file2; 144 | } 145 | catch (UriFormatException e) 146 | { 147 | System.Diagnostics.Trace.WriteLine("Exception " + e.Message); 148 | } 149 | 150 | return false; 151 | } 152 | 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/IntegrationTest Library/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using System.Reflection; 5 | using System.Diagnostics; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.ComponentModel.Design; 9 | using System.Runtime.InteropServices; 10 | using Microsoft.VisualStudio.Shell.Interop; 11 | using Microsoft.VisualStudio.Shell; 12 | using EnvDTE; 13 | using EnvDTE80; 14 | using Microsoft.Win32; 15 | using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; 16 | using Microsoft.VisualStudio.TestTools.UnitTesting; 17 | using Microsoft.VSSDK.Tools.VsIdeTesting; 18 | using Microsoft.VisualStudio; 19 | 20 | namespace Microsoft.VsSDK.IntegrationTestLibrary 21 | { 22 | /// 23 | /// 24 | public class TestUtils 25 | { 26 | 27 | #region Methods: Handling embedded resources 28 | /// 29 | /// Gets the embedded file identified by the resource name, and converts the 30 | /// file into a string. 31 | /// 32 | /// In VS, is DefaultNamespace.FileName? 33 | /// 34 | public static string GetEmbeddedStringResource(Assembly assembly, string resourceName) 35 | { 36 | string result = null; 37 | 38 | // Use the .NET procedure for loading a file embedded in the assembly 39 | Stream stream = assembly.GetManifestResourceStream(resourceName); 40 | if (stream != null) 41 | { 42 | // Convert bytes to string 43 | byte[] fileContentsAsBytes = new byte[stream.Length]; 44 | stream.Read(fileContentsAsBytes, 0, (int)stream.Length); 45 | result = Encoding.Default.GetString(fileContentsAsBytes); 46 | } 47 | else 48 | { 49 | // Embedded resource not found - list available resources 50 | Debug.WriteLine("Unable to find the embedded resource file '" + resourceName + "'."); 51 | Debug.WriteLine(" Available resources:"); 52 | foreach (string aResourceName in assembly.GetManifestResourceNames()) 53 | { 54 | Debug.WriteLine(" " + aResourceName); 55 | } 56 | } 57 | 58 | return result; 59 | } 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | /// 66 | /// 67 | public static void WriteEmbeddedResourceToFile(Assembly assembly, string embeddedResourceName, string fileName) 68 | { 69 | // Get file contents 70 | string fileContents = GetEmbeddedStringResource(assembly, embeddedResourceName); 71 | if (fileContents == null) 72 | throw new ApplicationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName); 73 | 74 | // Write to file 75 | StreamWriter sw = new StreamWriter(fileName); 76 | sw.Write(fileContents); 77 | sw.Close(); 78 | } 79 | 80 | /// 81 | /// Writes an embedded resource to a file. 82 | /// 83 | /// The name of the assembly that the embedded resource is defined. 84 | /// The name of the embedded resource. 85 | /// The file to write the embedded resource's content. 86 | public static void WriteEmbeddedResourceToBinaryFile(Assembly assembly, string embeddedResourceName, string fileName) 87 | { 88 | // Get file contents 89 | Stream stream = assembly.GetManifestResourceStream(embeddedResourceName); 90 | if (stream == null) 91 | throw new InvalidOperationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName); 92 | 93 | // Write to file 94 | BinaryWriter sw = null; 95 | FileStream fs = null; 96 | try 97 | { 98 | byte[] fileContentsAsBytes = new byte[stream.Length]; 99 | stream.Read(fileContentsAsBytes, 0, (int)stream.Length); 100 | 101 | FileMode mode = FileMode.CreateNew; 102 | if (File.Exists(fileName)) 103 | { 104 | mode = FileMode.Truncate; 105 | } 106 | 107 | fs = new FileStream(fileName, mode); 108 | 109 | sw = new BinaryWriter(fs); 110 | sw.Write(fileContentsAsBytes); 111 | } 112 | finally 113 | { 114 | if (fs != null) 115 | { 116 | fs.Close(); 117 | } 118 | if (sw != null) 119 | { 120 | sw.Close(); 121 | } 122 | } 123 | } 124 | 125 | #endregion 126 | 127 | #region Methods: Handling temporary files and directories 128 | /// 129 | /// Returns the first available file name on the form 130 | /// [baseFileName]i.[extension] 131 | /// where [i] starts at 1 and increases until there is an available file name 132 | /// in the given directory. Also creates an empty file with that name to mark 133 | /// that file as occupied. 134 | /// 135 | /// Directory that the file should live in. 136 | /// 137 | /// may be null, in which case the .[extension] part 138 | /// is not added. 139 | /// Full file name. 140 | public static string GetNewFileName(string directory, string baseFileName, string extension) 141 | { 142 | // Get the new file name 143 | string fileName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseFileName, extension); 144 | 145 | // Create an empty file to mark it as taken 146 | StreamWriter sw = new StreamWriter(fileName); 147 | 148 | sw.Write(""); 149 | sw.Close(); 150 | return fileName; 151 | } 152 | /// 153 | /// Returns the first available directory name on the form 154 | /// [baseDirectoryName]i 155 | /// where [i] starts at 1 and increases until there is an available directory name 156 | /// in the given directory. Also creates the directory to mark it as occupied. 157 | /// 158 | /// Directory that the file should live in. 159 | /// 160 | /// Full directory name. 161 | public static string GetNewDirectoryName(string directory, string baseDirectoryName) 162 | { 163 | // Get the new file name 164 | string directoryName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseDirectoryName, null); 165 | 166 | // Create an empty directory to make it as occupied 167 | Directory.CreateDirectory(directoryName); 168 | 169 | return directoryName; 170 | } 171 | 172 | /// 173 | /// 174 | /// 175 | /// 176 | /// 177 | /// 178 | /// 179 | private static string GetNewFileOrDirectoryNameWithoutCreatingAnything(string directory, string baseFileName, string extension) 180 | { 181 | // - get a file name that we can use 182 | string fileName; 183 | int i = 1; 184 | 185 | string fullFileName = null; 186 | while (true) 187 | { 188 | // construct next file name 189 | fileName = baseFileName + i; 190 | if (extension != null) 191 | fileName += '.' + extension; 192 | 193 | // check if that file exists in the directory 194 | fullFileName = Path.Combine(directory, fileName); 195 | 196 | if (!File.Exists(fullFileName) && !Directory.Exists(fullFileName)) 197 | break; 198 | else 199 | i++; 200 | } 201 | 202 | return fullFileName; 203 | } 204 | #endregion 205 | 206 | #region Methods: Handling solutions 207 | /// 208 | /// Closes the currently open solution (if any), and creates a new solution with the given name. 209 | /// 210 | /// Name of new solution. 211 | public void CreateEmptySolution(string directory, string solutionName) 212 | { 213 | CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave); 214 | 215 | string solutionDirectory = GetNewDirectoryName(directory, solutionName); 216 | 217 | // Create and force save solution 218 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); 219 | solutionService.CreateSolution(solutionDirectory, solutionName, (uint)__VSCREATESOLUTIONFLAGS.CSF_SILENT); 220 | solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0); 221 | DTE dte = VsIdeTestHostContext.Dte; 222 | Assert.AreEqual(solutionName + ".sln", Path.GetFileName(dte.Solution.FileName), "Newly created solution has wrong Filename"); 223 | } 224 | 225 | public void CloseCurrentSolution(__VSSLNSAVEOPTIONS saveoptions) 226 | { 227 | // Get solution service 228 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); 229 | 230 | // Close already open solution 231 | solutionService.CloseSolutionElement((uint)saveoptions, null, 0); 232 | } 233 | 234 | public void ForceSaveSolution() 235 | { 236 | // Get solution service 237 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); 238 | 239 | // Force-save the solution 240 | solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0); 241 | } 242 | 243 | /// 244 | /// Get current number of open project in solution 245 | /// 246 | /// 247 | public int ProjectCount() 248 | { 249 | // Get solution service 250 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); 251 | object projectCount; 252 | solutionService.GetProperty((int)__VSPROPID.VSPROPID_ProjectCount, out projectCount); 253 | return (int)projectCount; 254 | } 255 | #endregion 256 | 257 | #region Methods: Handling projects 258 | /// 259 | /// Creates a project. 260 | /// 261 | /// Name of new project. 262 | /// Name of project template to use 263 | /// language 264 | /// New project. 265 | public void CreateProjectFromTemplate(string projectName, string templateName, string language, bool exclusive) 266 | { 267 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); 268 | 269 | Solution2 sol = dte.Solution as Solution2; 270 | string projectTemplate = sol.GetProjectTemplate(templateName, language); 271 | 272 | // - project name and directory 273 | string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName; 274 | string projectDirectory = GetNewDirectoryName(solutionDirectory, projectName); 275 | 276 | dte.Solution.AddFromTemplate(projectTemplate, projectDirectory, projectName, false); 277 | } 278 | #endregion 279 | 280 | #region Methods: Handling project items 281 | /// 282 | /// Create a new item in the project 283 | /// 284 | /// the parent collection for the new item 285 | /// 286 | /// 287 | /// 288 | /// 289 | public ProjectItem AddNewItemFromVsTemplate(ProjectItems parent, string templateName, string language, string name) 290 | { 291 | if (parent == null) 292 | throw new ArgumentException("project"); 293 | if (name == null) 294 | throw new ArgumentException("name"); 295 | 296 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); 297 | 298 | Solution2 sol = dte.Solution as Solution2; 299 | 300 | string filename = sol.GetProjectItemTemplate(templateName, language); 301 | 302 | parent.AddFromTemplate(filename, name); 303 | 304 | return parent.Item(name); 305 | } 306 | 307 | /// 308 | /// Save an open document. 309 | /// 310 | /// for filebased documents this is the full path to the document 311 | public void SaveDocument(string documentMoniker) 312 | { 313 | // Get document cookie and hierarchy for the file 314 | IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable)); 315 | uint docCookie; 316 | IntPtr docData; 317 | IVsHierarchy hierarchy; 318 | uint itemId; 319 | runningDocumentTableService.FindAndLockDocument( 320 | (uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock, 321 | documentMoniker, 322 | out hierarchy, 323 | out itemId, 324 | out docData, 325 | out docCookie); 326 | 327 | // Save the document 328 | IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); 329 | solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, hierarchy, docCookie); 330 | } 331 | 332 | public void CloseInEditorWithoutSaving(string fullFileName) 333 | { 334 | // Get the RDT service 335 | IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable)); 336 | Assert.IsNotNull(runningDocumentTableService, "Failed to get the Running Document Table Service"); 337 | 338 | // Get our document cookie and hierarchy for the file 339 | uint docCookie; 340 | IntPtr docData; 341 | IVsHierarchy hierarchy; 342 | uint itemId; 343 | runningDocumentTableService.FindAndLockDocument( 344 | (uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock, 345 | fullFileName, 346 | out hierarchy, 347 | out itemId, 348 | out docData, 349 | out docCookie); 350 | 351 | // Get the SolutionService 352 | IVsSolution solutionService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)) as IVsSolution; 353 | Assert.IsNotNull(solutionService, "Failed to get IVsSolution service"); 354 | 355 | // Close the document 356 | solutionService.CloseSolutionElement( 357 | (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave, 358 | hierarchy, 359 | docCookie); 360 | } 361 | #endregion 362 | 363 | #region Methods: Handling Toolwindows 364 | public bool CanFindToolwindow(Guid persistenceGuid) 365 | { 366 | IVsUIShell uiShellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; 367 | Assert.IsNotNull(uiShellService); 368 | IVsWindowFrame windowFrame; 369 | int hr = uiShellService.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out windowFrame); 370 | Assert.IsTrue(hr == VSConstants.S_OK); 371 | 372 | return (windowFrame != null); 373 | } 374 | #endregion 375 | 376 | #region Methods: Loading packages 377 | public IVsPackage LoadPackage(Guid packageGuid) 378 | { 379 | IVsShell shellService = (IVsShell)VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)); 380 | IVsPackage package; 381 | shellService.LoadPackage(ref packageGuid, out package); 382 | Assert.IsNotNull(package, "Failed to load package"); 383 | return package; 384 | } 385 | #endregion 386 | 387 | /// 388 | /// Executes a Command (menu item) in the given context 389 | /// 390 | public void ExecuteCommand(CommandID cmd) 391 | { 392 | object Customin = null; 393 | object Customout = null; 394 | string guidString = cmd.Guid.ToString("B").ToUpper(); 395 | int cmdId = cmd.ID; 396 | DTE dte = VsIdeTestHostContext.Dte; 397 | dte.Commands.Raise(guidString, cmdId, ref Customin, ref Customout); 398 | } 399 | 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/SmartPaster2013/SmartPaster2013_IntegrationTests/Key.snk -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/MenuItemTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.ComponentModel.Design; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Microsoft.VisualStudio.OLE.Interop; 6 | using Microsoft.VisualStudio.Shell.Interop; 7 | using Microsoft.VisualStudio.Shell; 8 | using Microsoft.VsSDK.IntegrationTestLibrary; 9 | using Microsoft.VSSDK.Tools.VsIdeTesting; 10 | 11 | namespace SmartPaster2013_IntegrationTests 12 | { 13 | [TestClass()] 14 | public class MenuItemTest 15 | { 16 | private delegate void ThreadInvoker(); 17 | 18 | private TestContext testContextInstance; 19 | 20 | /// 21 | ///Gets or sets the test context which provides 22 | ///information about and functionality for the current test run. 23 | /// 24 | public TestContext TestContext 25 | { 26 | get 27 | { 28 | return testContextInstance; 29 | } 30 | set 31 | { 32 | testContextInstance = value; 33 | } 34 | } 35 | 36 | /// 37 | ///A test for lauching the command and closing the associated dialogbox 38 | /// 39 | [TestMethod()] 40 | [HostType("VS IDE")] 41 | public void LaunchCommand() 42 | { 43 | UIThreadInvoker.Invoke((ThreadInvoker)delegate() 44 | { 45 | CommandID menuItemCmd = new CommandID(SmartPaster2013.GuidList.guidSmartPaster2013CmdSet, (int)SmartPaster2013.PkgCmdIDList.cmdidPasteAsComment); 46 | 47 | // Create the DialogBoxListener Thread. 48 | string expectedDialogBoxText = string.Format(CultureInfo.CurrentCulture, "{0}\n\nInside {1}.MenuItemCallback()", "SmartPaster2013", "MartinWilley.SmartPaster2013.SmartPaster2013Package"); 49 | DialogBoxPurger purger = new DialogBoxPurger(NativeMethods.IDOK, expectedDialogBoxText); 50 | 51 | try 52 | { 53 | purger.Start(); 54 | 55 | TestUtils testUtils = new TestUtils(); 56 | testUtils.ExecuteCommand(menuItemCmd); 57 | } 58 | finally 59 | { 60 | Assert.IsTrue(purger.WaitForDialogThreadToTerminate(), "The dialog box has not shown"); 61 | } 62 | }); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/PackageTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | using Microsoft.VSSDK.Tools.VsIdeTesting; 7 | using Microsoft.VisualStudio.Shell.Interop; 8 | using Microsoft.VisualStudio.Shell; 9 | using EnvDTE; 10 | 11 | namespace SmartPaster2013_IntegrationTests 12 | { 13 | /// 14 | /// Integration test for package validation 15 | /// 16 | [TestClass] 17 | public class PackageTest 18 | { 19 | private delegate void ThreadInvoker(); 20 | 21 | private TestContext testContextInstance; 22 | 23 | /// 24 | ///Gets or sets the test context which provides 25 | ///information about and functionality for the current test run. 26 | /// 27 | public TestContext TestContext 28 | { 29 | get 30 | { 31 | return testContextInstance; 32 | } 33 | set 34 | { 35 | testContextInstance = value; 36 | } 37 | } 38 | 39 | [TestMethod] 40 | [HostType("VS IDE")] 41 | public void PackageLoadTest() 42 | { 43 | UIThreadInvoker.Invoke((ThreadInvoker)delegate() 44 | { 45 | 46 | //Get the Shell Service 47 | IVsShell shellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)) as IVsShell; 48 | Assert.IsNotNull(shellService); 49 | 50 | //Validate package load 51 | IVsPackage package; 52 | Guid packageGuid = new Guid(SmartPaster2013.GuidList.guidSmartPaster2013PkgString); 53 | Assert.IsTrue(0 == shellService.LoadPackage(ref packageGuid, out package)); 54 | Assert.IsNotNull(package, "Package failed to load"); 55 | 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/SignOff-Tests/CPPProjectTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Microsoft.VsSDK.IntegrationTestLibrary; 6 | using Microsoft.VSSDK.Tools.VsIdeTesting; 7 | using EnvDTE; 8 | using System.IO; 9 | 10 | namespace SmartPaster2013_IntegrationTests.IntegrationTests 11 | { 12 | [TestClass] 13 | public class CPPProjectTests 14 | { 15 | #region fields 16 | private delegate void ThreadInvoker(); 17 | private TestContext _testContext; 18 | #endregion 19 | 20 | #region properties 21 | /// 22 | ///Gets or sets the test context which provides 23 | ///information about and functionality for the current test run. 24 | /// 25 | public TestContext TestContext 26 | { 27 | get { return _testContext; } 28 | set { _testContext = value; } 29 | } 30 | #endregion 31 | 32 | #region ctors 33 | public CPPProjectTests() 34 | { 35 | } 36 | #endregion 37 | 38 | #region Additional test attributes 39 | // 40 | // You can use the following additional attributes as you write your tests: 41 | // 42 | // Use ClassInitialize to run code before running the first test in the class 43 | // [ClassInitialize()] 44 | // public static void MyClassInitialize(TestContext testContext) { } 45 | // 46 | // Use ClassCleanup to run code after all tests in a class have run 47 | // [ClassCleanup()] 48 | // public static void MyClassCleanup() { } 49 | // 50 | // Use TestInitialize to run code before running each test 51 | // [TestInitialize()] 52 | // public void MyTestInitialize() { } 53 | // 54 | // Use TestCleanup to run code after each test has run 55 | // [TestCleanup()] 56 | // public void MyTestCleanup() { } 57 | // 58 | #endregion 59 | 60 | [HostType("VS IDE")] 61 | [TestMethod] 62 | public void CPPWinformsApplication() 63 | { 64 | UIThreadInvoker.Invoke((ThreadInvoker)delegate() 65 | { 66 | //Solution and project creation parameters 67 | string solutionName = "CPPWinApp"; 68 | string projectName = "CPPWinApp"; 69 | 70 | //Template parameters 71 | string projectType = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"; 72 | string projectTemplateName = Path.Combine("vcNet", "mc++appwiz.vsz"); 73 | 74 | string itemTemplateName = "newc++file.cpp"; 75 | string newFileName = "Test.cpp"; 76 | 77 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); 78 | 79 | TestUtils testUtils = new TestUtils(); 80 | 81 | testUtils.CreateEmptySolution(TestContext.TestDir, solutionName); 82 | Assert.AreEqual(0, testUtils.ProjectCount()); 83 | 84 | //Add new CPP Windows application project to existing solution 85 | string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName; 86 | string projectDirectory = TestUtils.GetNewDirectoryName(solutionDirectory, projectName); 87 | string projectTemplatePath = Path.Combine(dte.Solution.get_TemplatePath(projectType), projectTemplateName); 88 | Assert.IsTrue(File.Exists(projectTemplatePath), string.Format("Could not find template file: {0}", projectTemplatePath)); 89 | dte.Solution.AddFromTemplate(projectTemplatePath, projectDirectory, projectName, false); 90 | 91 | //Verify that the new project has been added to the solution 92 | Assert.AreEqual(1, testUtils.ProjectCount()); 93 | 94 | //Get the project 95 | Project project = dte.Solution.Item(1); 96 | Assert.IsNotNull(project); 97 | Assert.IsTrue(string.Compare(project.Name, projectName, StringComparison.InvariantCultureIgnoreCase) == 0); 98 | 99 | //Verify Adding new code file to project 100 | string newItemTemplatePath = Path.Combine(dte.Solution.ProjectItemsTemplatePath(projectType), itemTemplateName); 101 | Assert.IsTrue(File.Exists(newItemTemplatePath)); 102 | ProjectItem item = project.ProjectItems.AddFromTemplate(newItemTemplatePath, newFileName); 103 | Assert.IsNotNull(item); 104 | 105 | }); 106 | } 107 | 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/SignOff-Tests/CSharpProjectTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Microsoft.VsSDK.IntegrationTestLibrary; 6 | using Microsoft.VSSDK.Tools.VsIdeTesting; 7 | 8 | namespace SmartPaster2013_IntegrationTests.IntegrationTests 9 | { 10 | [TestClass] 11 | public class CSharpProjectTests 12 | { 13 | #region fields 14 | private delegate void ThreadInvoker(); 15 | private TestContext _testContext; 16 | #endregion 17 | 18 | #region properties 19 | /// 20 | ///Gets or sets the test context which provides 21 | ///information about and functionality for the current test run. 22 | /// 23 | public TestContext TestContext 24 | { 25 | get { return _testContext; } 26 | set { _testContext = value; } 27 | } 28 | #endregion 29 | 30 | #region ctors 31 | public CSharpProjectTests() 32 | { 33 | } 34 | #endregion 35 | 36 | #region Additional test attributes 37 | // 38 | // You can use the following additional attributes as you write your tests: 39 | // 40 | // Use ClassInitialize to run code before running the first test in the class 41 | // [ClassInitialize()] 42 | // public static void MyClassInitialize(TestContext testContext) { } 43 | // 44 | // Use ClassCleanup to run code after all tests in a class have run 45 | // [ClassCleanup()] 46 | // public static void MyClassCleanup() { } 47 | // 48 | // Use TestInitialize to run code before running each test 49 | // [TestInitialize()] 50 | // public void MyTestInitialize() { } 51 | // 52 | // Use TestCleanup to run code after each test has run 53 | // [TestCleanup()] 54 | // public void MyTestCleanup() { } 55 | // 56 | #endregion 57 | 58 | [TestMethod] 59 | [HostType("VS IDE")] 60 | public void WinformsApplication() 61 | { 62 | UIThreadInvoker.Invoke((ThreadInvoker)delegate() 63 | { 64 | TestUtils testUtils = new TestUtils(); 65 | 66 | testUtils.CreateEmptySolution(TestContext.TestDir, "CSWinApp"); 67 | Assert.AreEqual(0, testUtils.ProjectCount()); 68 | 69 | //Create Winforms application project 70 | //TestUtils.CreateProjectFromTemplate("MyWindowsApp", "Windows Application", "CSharp", false); 71 | //Assert.AreEqual(1, TestUtils.ProjectCount()); 72 | 73 | //TODO Verify that we can debug launch the application 74 | 75 | //TODO Set Break point and verify that will hit 76 | 77 | //TODO Verify Adding new project item to project 78 | 79 | }); 80 | } 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/SignOff-Tests/SolutionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using Microsoft.VisualStudio.Shell.Interop; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | using Microsoft.VSSDK.Tools.VsIdeTesting; 7 | using EnvDTE; 8 | using System.IO; 9 | using Microsoft.VsSDK.IntegrationTestLibrary; 10 | 11 | 12 | namespace SmartPaster2013_IntegrationTests.IntegrationTests 13 | { 14 | [TestClass] 15 | public class SolutionTests 16 | { 17 | #region fields 18 | private delegate void ThreadInvoker(); 19 | private TestContext _testContext; 20 | #endregion 21 | 22 | #region properties 23 | /// 24 | ///Gets or sets the test context which provides 25 | ///information about and functionality for the current test run. 26 | /// 27 | public TestContext TestContext 28 | { 29 | get { return _testContext; } 30 | set { _testContext = value; } 31 | } 32 | #endregion 33 | 34 | 35 | #region ctors 36 | public SolutionTests() 37 | { 38 | } 39 | 40 | #endregion 41 | 42 | [TestMethod] 43 | [HostType("VS IDE")] 44 | public void CreateEmptySolution() 45 | { 46 | UIThreadInvoker.Invoke((ThreadInvoker)delegate() 47 | { 48 | TestUtils testUtils = new TestUtils(); 49 | testUtils.CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave); 50 | testUtils.CreateEmptySolution(TestContext.TestDir, "EmptySolution"); 51 | }); 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/SignOff-Tests/VBProjectTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Microsoft.VsSDK.IntegrationTestLibrary; 6 | using Microsoft.VSSDK.Tools.VsIdeTesting; 7 | using EnvDTE; 8 | 9 | namespace SmartPaster2013_IntegrationTests.IntegrationTests 10 | { 11 | [TestClass] 12 | public class VisualBasicProjectTests 13 | { 14 | #region fields 15 | private delegate void ThreadInvoker(); 16 | private TestContext _testContext; 17 | #endregion 18 | 19 | #region properties 20 | /// 21 | ///Gets or sets the test context which provides 22 | ///information about and functionality for the current test run. 23 | /// 24 | public TestContext TestContext 25 | { 26 | get { return _testContext; } 27 | set { _testContext = value; } 28 | } 29 | #endregion 30 | 31 | #region ctors 32 | public VisualBasicProjectTests() 33 | { 34 | } 35 | #endregion 36 | 37 | #region Additional test attributes 38 | // 39 | // You can use the following additional attributes as you write your tests: 40 | // 41 | // Use ClassInitialize to run code before running the first test in the class 42 | // [ClassInitialize()] 43 | // public static void MyClassInitialize(TestContext testContext) { } 44 | // 45 | // Use ClassCleanup to run code after all tests in a class have run 46 | // [ClassCleanup()] 47 | // public static void MyClassCleanup() { } 48 | // 49 | // Use TestInitialize to run code before running each test 50 | // [TestInitialize()] 51 | // public void MyTestInitialize() { } 52 | // 53 | // Use TestCleanup to run code after each test has run 54 | // [TestCleanup()] 55 | // public void MyTestCleanup() { } 56 | // 57 | #endregion 58 | 59 | [HostType("VS IDE")] 60 | [TestMethod] 61 | public void VBWinformsApplication() 62 | { 63 | UIThreadInvoker.Invoke((ThreadInvoker)delegate() 64 | { 65 | //Solution and project creation parameters 66 | string solutionName = "VBWinApp"; 67 | string projectName = "VBWinApp"; 68 | 69 | //Template parameters 70 | string language = "VisualBasic"; 71 | string projectTemplateName = "WindowsApplication.Zip"; 72 | string itemTemplateName = "CodeFile.zip"; 73 | string newFileName = "Test.vb"; 74 | 75 | DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); 76 | 77 | TestUtils testUtils = new TestUtils(); 78 | 79 | testUtils.CreateEmptySolution(TestContext.TestDir, solutionName); 80 | Assert.AreEqual(0, testUtils.ProjectCount()); 81 | 82 | //Add new Windows application project to existing solution 83 | testUtils.CreateProjectFromTemplate(projectName, projectTemplateName, language, false); 84 | 85 | //Verify that the new project has been added to the solution 86 | Assert.AreEqual(1, testUtils.ProjectCount()); 87 | 88 | //Get the project 89 | Project project = dte.Solution.Item(1); 90 | Assert.IsNotNull(project); 91 | Assert.IsTrue(string.Compare(project.Name, projectName, StringComparison.InvariantCultureIgnoreCase) == 0); 92 | 93 | //Verify Adding new code file to project 94 | ProjectItem newCodeFileItem = testUtils.AddNewItemFromVsTemplate(project.ProjectItems, itemTemplateName, language, newFileName); 95 | Assert.IsNotNull(newCodeFileItem, "Could not create new project item"); 96 | 97 | }); 98 | } 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_IntegrationTests/SmartPaster2013_IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 2.0 7 | {089197FF-F1AF-4AA3-9C8F-79D3381CB0D1} 8 | Library 9 | Properties 10 | SmartPaster2013_IntegrationTests 11 | SmartPaster2013_IntegrationTests 12 | v4.5 13 | 512 14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | Key.snk 35 | 36 | 37 | true 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | true 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2} 78 | SmartPaster2013 79 | 80 | 81 | 82 | 89 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martinjw/SmartPaster2013/a65224953b746cf4de4634d38750b068cd2658b4/SmartPaster2013/SmartPaster2013_UnitTests/Key.snk -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/MenuItemTests/MenuItemCallback.cs: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | This code is licensed under the Visual Studio SDK license terms. 5 | THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | 10 | ***************************************************************************/ 11 | 12 | using System; 13 | using System.Collections; 14 | using System.Text; 15 | using System.Reflection; 16 | using System.ComponentModel.Design; 17 | using Microsoft.VsSDK.UnitTestLibrary; 18 | using Microsoft.VisualStudio.Shell.Interop; 19 | using Microsoft.VisualStudio.TestTools.UnitTesting; 20 | using Microsoft.VisualStudio.Shell; 21 | using SmartPaster2013; 22 | 23 | namespace SmartPaster2013_UnitTests.MenuItemTests 24 | { 25 | [TestClass()] 26 | public class MenuItemTest 27 | { 28 | /// 29 | /// Verify that a new menu command object gets added to the OleMenuCommandService. 30 | /// This action takes place In the Initialize method of the Package object 31 | /// 32 | [TestMethod] 33 | public void InitializeMenuCommand() 34 | { 35 | // Create the package 36 | IVsPackage package = new SmartPaster2013Package() as IVsPackage; 37 | Assert.IsNotNull(package, "The object does not implement IVsPackage"); 38 | 39 | // Create a basic service provider 40 | OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); 41 | 42 | // Site the package 43 | Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); 44 | 45 | //Verify that the menu command can be found 46 | CommandID menuCommandID = new CommandID(SmartPaster2013.GuidList.guidSmartPaster2013CmdSet, (int)SmartPaster2013.PkgCmdIDList.cmdidPasteAsComment); 47 | System.Reflection.MethodInfo info = typeof(Package).GetMethod("GetService", BindingFlags.Instance | BindingFlags.NonPublic); 48 | Assert.IsNotNull(info); 49 | OleMenuCommandService mcs = info.Invoke(package, new object[] { (typeof(IMenuCommandService)) }) as OleMenuCommandService; 50 | Assert.IsNotNull(mcs.FindCommand(menuCommandID)); 51 | } 52 | 53 | //[TestMethod] 54 | //public void MenuItemCallback() 55 | //{ 56 | // // Create the package 57 | // IVsPackage package = new SmartPaster2013Package() as IVsPackage; 58 | // Assert.IsNotNull(package, "The object does not implement IVsPackage"); 59 | 60 | // // Create a basic service provider 61 | // OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); 62 | 63 | // // Create a UIShell service mock and proffer the service so that it can called from the MenuItemCallback method 64 | // BaseMock uishellMock = UIShellServiceMock.GetUiShellInstance(); 65 | // serviceProvider.AddService(typeof(SVsUIShell), uishellMock, true); 66 | 67 | // // Site the package 68 | // Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); 69 | 70 | // //Invoke private method on package class and observe that the method does not throw 71 | // System.Reflection.MethodInfo info = package.GetType().GetMethod("MenuItemCallback", BindingFlags.Instance | BindingFlags.NonPublic); 72 | // Assert.IsNotNull(info, "Failed to get the private method MenuItemCallback throug refplection"); 73 | // info.Invoke(package, new object[] { null, null }); 74 | 75 | // //Clean up services 76 | // serviceProvider.RemoveService(typeof(SVsUIShell)); 77 | 78 | //} 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/MenuItemTests/UIShellServiceMock.cs: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | This code is licensed under the Visual Studio SDK license terms. 5 | THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | 10 | ***************************************************************************/ 11 | 12 | using System; 13 | using Microsoft.VisualStudio; 14 | using Microsoft.VisualStudio.Shell.Interop; 15 | using Microsoft.VsSDK.UnitTestLibrary; 16 | 17 | namespace SmartPaster2013_UnitTests 18 | { 19 | static class UIShellServiceMock 20 | { 21 | private static GenericMockFactory uiShellFactory; 22 | 23 | #region UiShell Getters 24 | /// 25 | /// Returns an IVsUiShell that does not implement any methods 26 | /// 27 | /// 28 | internal static BaseMock GetUiShellInstance() 29 | { 30 | if (uiShellFactory == null) 31 | { 32 | uiShellFactory = new GenericMockFactory("UiShell", new Type[] { typeof(IVsUIShell), typeof(IVsUIShellOpenDocument) }); 33 | } 34 | BaseMock uiShell = uiShellFactory.GetInstance(); 35 | return uiShell; 36 | } 37 | 38 | /// 39 | /// Get an IVsUiShell that implements SetWaitCursor, SaveDocDataToFile, ShowMessageBox 40 | /// 41 | /// uishell mock 42 | internal static BaseMock GetUiShellInstance0() 43 | { 44 | BaseMock uiShell = GetUiShellInstance(); 45 | string name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "SetWaitCursor"); 46 | uiShell.AddMethodCallback(name, new EventHandler(SetWaitCursorCallBack)); 47 | 48 | name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "SaveDocDataToFile"); 49 | uiShell.AddMethodCallback(name, new EventHandler(SaveDocDataToFileCallBack)); 50 | 51 | name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "ShowMessageBox"); 52 | uiShell.AddMethodCallback(name, new EventHandler(ShowMessageBoxCallBack)); 53 | return uiShell; 54 | } 55 | #endregion 56 | 57 | #region Callbacks 58 | private static void SetWaitCursorCallBack(object caller, CallbackArgs arguments) 59 | { 60 | arguments.ReturnValue = VSConstants.S_OK; 61 | } 62 | 63 | private static void SaveDocDataToFileCallBack(object caller, CallbackArgs arguments) 64 | { 65 | arguments.ReturnValue = VSConstants.S_OK; 66 | } 67 | 68 | private static void ShowMessageBoxCallBack(object caller, CallbackArgs arguments) 69 | { 70 | arguments.ReturnValue = VSConstants.S_OK; 71 | arguments.SetParameter(10, (int)System.Windows.Forms.DialogResult.Yes); 72 | } 73 | 74 | #endregion 75 | } 76 | } -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/PackageTest.cs: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | This code is licensed under the Visual Studio SDK license terms. 5 | THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | 10 | ***************************************************************************/ 11 | 12 | using System; 13 | using System.Collections; 14 | using System.Text; 15 | using System.Reflection; 16 | using Microsoft.VsSDK.UnitTestLibrary; 17 | using Microsoft.VisualStudio.Shell.Interop; 18 | using Microsoft.VisualStudio.TestTools.UnitTesting; 19 | using SmartPaster2013; 20 | 21 | namespace SmartPaster2013_UnitTests 22 | { 23 | [TestClass()] 24 | public class PackageTest 25 | { 26 | [TestMethod()] 27 | public void CreateInstance() 28 | { 29 | SmartPaster2013Package package = new SmartPaster2013Package(); 30 | } 31 | 32 | [TestMethod()] 33 | public void IsIVsPackage() 34 | { 35 | SmartPaster2013Package package = new SmartPaster2013Package(); 36 | Assert.IsNotNull(package as IVsPackage, "The object does not implement IVsPackage"); 37 | } 38 | 39 | [TestMethod()] 40 | public void SetSite() 41 | { 42 | // Create the package 43 | IVsPackage package = new SmartPaster2013Package() as IVsPackage; 44 | Assert.IsNotNull(package, "The object does not implement IVsPackage"); 45 | 46 | // Create a basic service provider 47 | OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); 48 | 49 | // Site the package 50 | Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); 51 | 52 | // Unsite the package 53 | Assert.AreEqual(0, package.SetSite(null), "SetSite(null) did not return S_OK"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/Scratchpad.vb: -------------------------------------------------------------------------------- 1 |  2 | '我给你一本书 。 3 | 'This has a tab and " quotes but this \t is not an escape 4 | 5 | 6 | 'Not a real VB class, just a file with BuildAction None and a vb extension so we can test SmartPaster 7 | Public Class ScratchPad 8 | 9 | Public Function GetValue(ByVal id As Integer) As String 10 | Dim a = "'我给你一本书 。" & Environment.NewLine & _ 11 | "'This has a tab and "" quotes but this \t is not an escape" 12 | Dim s As String = 13 | .Value 17 | ''我给你一本书 。 18 | ''This has a tab and " quotes but this \t is not an escape 19 | Dim sb As New System.Text.StringBuilder(73) 20 | sb.AppendLine("'我给你一本书 。") 21 | sb.AppendLine("'This has a tab and "" quotes but this \t is not an escape") 22 | 23 | 24 | Return "value" 25 | End Function 26 | 27 | Public Sub Void(ByVal value As String) 28 | 29 | End Sub 30 | 31 | End Class -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/SmartFormatterTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using SmartPaster2013; 4 | 5 | namespace SmartPaster2013_UnitTests 6 | { 7 | [TestClass] 8 | public class SmartFormatterTests 9 | { 10 | /* 11 | 我给你一本书 。 12 | This has a tab and " quotes but this \t is not an escape 13 | */ 14 | //我给你一本书 。 15 | //This has a tab and " quotes but this \t is not an escape 16 | 17 | private const string Original = "我给你一本书 。\r\nThis has a \t tab and \" quotes but this \\t is not an escape"; 18 | 19 | [TestMethod] 20 | public void TestVerbatimStringCs() 21 | { 22 | var result = SmartFormatter.StringinizeInCs(Original); 23 | 24 | //should look like this 25 | var s = @"我给你一本书 。 26 | This has a tab and "" quotes but this \t is not an escape"; 27 | 28 | //The line break is included, the double-quotes are doubled 29 | //In verbatim, tabs can't be escaped, so it's just included as a raw tab 30 | //a VS reformat may convert the tab to spaces 31 | Assert.AreEqual(@"@""我给你一本书 。 32 | This has a " + "\t tab and \"\" quotes but this \\t is not an escape\"", result); 33 | } 34 | 35 | [TestMethod] 36 | public void TestLiteralStringCs() 37 | { 38 | var result = SmartFormatter.LiterallyInCs(Original); 39 | 40 | //should look like this 41 | var s = "我给你一本书 。" + Environment.NewLine + 42 | "This has a tab and \" quotes but this \t is not an escape"; 43 | 44 | //Tab and quote is escaped, line is turned into NewLine 45 | Assert.AreEqual(@"""我给你一本书 。"" + Environment.NewLine + 46 | ""This has a \t tab and \"" quotes but this \\t is not an escape""", result); 47 | } 48 | 49 | [TestMethod] 50 | public void TestLiteralStringCsPath() 51 | { 52 | var path = @"C:\x\y\x"; 53 | var result = SmartFormatter.LiterallyInCs(path); 54 | Assert.AreEqual("\"C:\\\\x\\\\y\\\\x\"", result); 55 | } 56 | 57 | [TestMethod] 58 | public void TestLiteralStringCxxPath() 59 | { 60 | var path = @"C:\x\y\x"; 61 | var result = SmartFormatter.LiterallyInCxx(path); 62 | Assert.AreEqual("\"C:\\\\x\\\\y\\\\x\"", result); 63 | } 64 | 65 | [TestMethod] 66 | public void TestLiteralStringWithEmptyLinesCs() 67 | { 68 | var result = SmartFormatter.LiterallyInCs(@" 69 | 1 70 | 71 | 2 72 | "); 73 | 74 | //should look like this 75 | var s = "1" + Environment.NewLine + 76 | Environment.NewLine + 77 | "2"; 78 | 79 | //Tab and quote is escaped, line is turned into NewLine 80 | Assert.AreEqual("\"1\" + Environment.NewLine + \r\n\"\" + Environment.NewLine + \r\n\"2\"", result); 81 | } 82 | 83 | [TestMethod] 84 | public void TestLiteralWithLineBreak() 85 | { 86 | var s = @"select ""Id"", ""max"", ""Prefs"" 87 | from rs.""table"";"; 88 | var result = SmartFormatter.LiterallyInCs(s); 89 | 90 | Assert.AreEqual( 91 | "\"select \\\"Id\\\", \\\"max\\\", \\\"Prefs\\\"\" + Environment.NewLine + \r\n\" from rs.\\\"table\\\";\"", result); 92 | } 93 | 94 | 95 | [TestMethod] 96 | public void TestVerbatimStringVb() 97 | { 98 | var result = SmartFormatter.StringinizeInVb(Original); 99 | 100 | //Verbatim in VB 14. Double quoted, otherwise unchanged. 101 | Assert.AreEqual("\"我给你一本书 。\r\nThis has a \t tab and \"\" quotes but this \\t is not an escape\"", result); 102 | } 103 | 104 | 105 | [TestMethod] 106 | public void TestLiteralStringVb() 107 | { 108 | var result = SmartFormatter.LiterallyInVb(Original); 109 | 110 | //No verbatim in VB up to 14, so we just use literals with vbCrLf and line continuation 111 | Assert.AreEqual("\"我给你一本书 。\" & vbCrLf & _\r\n\"This has a \" & vbTab & \" tab and \"\"\"\" quotes but this \\t is not an escape\"", result); 112 | } 113 | 114 | 115 | [TestMethod] 116 | public void TestLiteralStringWithEmptyLinesVb() 117 | { 118 | var result = SmartFormatter.LiterallyInVb(@" 119 | 1 120 | 121 | 2 122 | "); 123 | 124 | //No verbatim in VB up to 14, so we just use literals with vbCrLf and line continuation 125 | //Arguably tab could be vbTab 126 | //You could use xml literals... 127 | Assert.AreEqual("\"1\" & vbCrLf & _\r\nvbCrLf & _\r\n\"2\"", result); 128 | } 129 | 130 | 131 | [TestMethod] 132 | public void TestCommentCs() 133 | { 134 | var result = SmartFormatter.CommentizeInCs(Original); 135 | 136 | //should look like this 137 | //我给你一本书 。 138 | //This has a tab and " quotes but this \t is not an escape 139 | 140 | //don't double quotes, just use line comment prefix 141 | //there's a trailing line break too 142 | Assert.AreEqual(@"//我给你一本书 。 143 | //This has a " + "\t tab and \" quotes but this \\t is not an escape\r\n", result); 144 | } 145 | 146 | [TestMethod] 147 | public void TestCommentVb() 148 | { 149 | var result = SmartFormatter.CommentizeInVb(Original); 150 | 151 | //don't double quotes, just use line comment prefix 152 | //there's a trailing line break too 153 | Assert.AreEqual(@"'我给你一本书 。 154 | 'This has a " + "\t tab and \" quotes but this \\t is not an escape\r\n", result); 155 | } 156 | 157 | [TestMethod] 158 | public void TestStringBuilderCs() 159 | { 160 | var result = SmartFormatter.StringbuilderizeInCs(Original, "sb"); 161 | 162 | //should look like this 163 | var sb = new System.Text.StringBuilder(68); 164 | sb.AppendLine(@"我给你一本书 。"); 165 | sb.AppendLine(@"This has a tab and "" quotes but this \t is not an escape"); 166 | 167 | //the single " becomes doubled, which becomes 4 here 168 | Assert.AreEqual(@"var sb = new System.Text.StringBuilder(68); 169 | sb.AppendLine(@""我给你一本书 。""); 170 | sb.AppendLine(@""This has a tab and """" quotes but this \t is not an escape""); 171 | ", result); 172 | } 173 | 174 | 175 | [TestMethod] 176 | public void TestStringBuilderVb() 177 | { 178 | var result = SmartFormatter.StringbuilderizeInVb(Original, "sb"); 179 | 180 | //the single " becomes doubled, which becomes 4 here 181 | Assert.AreEqual(@"Dim sb As New System.Text.StringBuilder(68) 182 | sb.AppendLine(""我给你一本书 。"") 183 | sb.AppendLine(""This has a tab and """" quotes but this \t is not an escape"") 184 | ", result); 185 | } 186 | 187 | 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/SmartPaster2013_UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 2.0 7 | {B8D186B6-3465-4F1D-8157-04367BE5C9ED} 8 | Library 9 | Properties 10 | SmartPaster2013_UnitTests 11 | SmartPaster2013_UnitTests 12 | v4.6 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | Key.snk 35 | 36 | 37 | true 38 | 39 | 40 | 41 | ..\..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll 42 | True 43 | 44 | 45 | ..\..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll 46 | True 47 | 48 | 49 | ..\..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll 50 | True 51 | 52 | 53 | ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll 54 | True 55 | 56 | 57 | ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll 58 | True 59 | 60 | 61 | ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll 62 | True 63 | 64 | 65 | ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll 66 | True 67 | 68 | 69 | ..\..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll 70 | True 71 | 72 | 73 | ..\..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll 74 | True 75 | 76 | 77 | 78 | true 79 | 80 | 81 | 82 | 83 | ..\..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll 84 | True 85 | 86 | 87 | ..\..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll 88 | True 89 | 90 | 91 | ..\..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll 92 | True 93 | 94 | 95 | ..\..\packages\Microsoft.VisualStudio.Threading.14.1.111\lib\net45\Microsoft.VisualStudio.Threading.dll 96 | True 97 | 98 | 99 | ..\..\packages\Microsoft.VisualStudio.Utilities.14.3.25407\lib\net45\Microsoft.VisualStudio.Utilities.dll 100 | True 101 | 102 | 103 | ..\..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll 104 | True 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | {E4C30299-C9D8-4860-BBB0-02F5887D3ED2} 132 | SmartPaster2013 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SmartPaster2013/SmartPaster2013_UnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /SmartPaster2013/VSPackage.resx: -------------------------------------------------------------------------------- 1 |  2 | 12 | 13 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | text/microsoft-resx 120 | 121 | 122 | 2.0 123 | 124 | 125 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | 128 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | 132 | SmartPaster2013 133 | 134 | 135 | Paste clipboard into comments or string builder 136 | 137 | 138 | Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 139 | 140 | -------------------------------------------------------------------------------- /SmartPaster2013/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SmartPaster2013/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /SmartPaster2013/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | SmartPaster2019 6 | Paste clipboard into comments or strings in C#, VB, C++ 7 | https://github.com/martinjw/SmartPaster2013 8 | License.txt 9 | Resources/Package.ico 10 | PasteAs Verbatim StringBuilder Comment 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /UnitTests.testsettings: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | This test run configuration is used for running the unit tests 9 | 10 | --------------------------------------------------------------------------------