├── .gitignore ├── Clippy.sln ├── Clippy.sln.DotSettings ├── Clippy ├── Clippy.cs ├── Clippy.csproj └── Properties │ └── AssemblyInfo.cs ├── ClippyTest ├── BasicUsage.cs ├── ClippyTest.csproj └── Properties │ └── AssemblyInfo.cs ├── LICENSE ├── README.md └── Sample ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs └── Sample.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | /*.suo 2 | /*.user 3 | /ClippyTest/bin 4 | /ClippyTest/obj 5 | /Clippy/bin 6 | /Clippy/obj 7 | /Sample/obj 8 | /Sample/bin 9 | /bin 10 | -------------------------------------------------------------------------------- /Clippy.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Clippy", "Clippy\Clippy.csproj", "{B6B651B1-13E1-4682-A303-CD0EB1BB41AF}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClippyTest", "ClippyTest\ClippyTest.csproj", "{F9B4726F-C7D5-4DDE-AF86-7DA246FF1F5A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "Sample\Sample.csproj", "{FE964C0A-C17B-476E-9906-DD12CC3C772F}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9C51FA4F-B589-4093-8E7B-C2C995C8B8D0}" 11 | ProjectSection(SolutionItems) = preProject 12 | LICENSE = LICENSE 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {B6B651B1-13E1-4682-A303-CD0EB1BB41AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {B6B651B1-13E1-4682-A303-CD0EB1BB41AF}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {B6B651B1-13E1-4682-A303-CD0EB1BB41AF}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {B6B651B1-13E1-4682-A303-CD0EB1BB41AF}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {F9B4726F-C7D5-4DDE-AF86-7DA246FF1F5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {F9B4726F-C7D5-4DDE-AF86-7DA246FF1F5A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {F9B4726F-C7D5-4DDE-AF86-7DA246FF1F5A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {F9B4726F-C7D5-4DDE-AF86-7DA246FF1F5A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {FE964C0A-C17B-476E-9906-DD12CC3C772F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {FE964C0A-C17B-476E-9906-DD12CC3C772F}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {FE964C0A-C17B-476E-9906-DD12CC3C772F}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {FE964C0A-C17B-476E-9906-DD12CC3C772F}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /Clippy.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | OK -------------------------------------------------------------------------------- /Clippy/Clippy.cs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2014 Kolibri 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | */ 25 | 26 | using System; 27 | using System.Runtime.InteropServices; 28 | using System.Text; 29 | 30 | // ReSharper disable once CheckNamespace 31 | namespace Kolibri 32 | { 33 | public class Clippy 34 | { 35 | [DllImport("kernel32.dll")] 36 | private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes); 37 | 38 | [DllImport("kernel32.dll")] 39 | private static extern uint GetLastError(); 40 | 41 | [DllImport("kernel32.dll")] 42 | private static extern IntPtr LocalFree(IntPtr hMem); 43 | 44 | [DllImport("kernel32.dll")] 45 | private static extern IntPtr GlobalFree(IntPtr hMem); 46 | 47 | [DllImport("kernel32.dll")] 48 | private static extern IntPtr GlobalLock(IntPtr hMem); 49 | 50 | [DllImport("kernel32.dll")] 51 | [return: MarshalAs(UnmanagedType.Bool)] 52 | private static extern bool GlobalUnlock(IntPtr hMem); 53 | 54 | [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] 55 | public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); 56 | 57 | [DllImport("user32.dll")] 58 | [return: MarshalAs(UnmanagedType.Bool)] 59 | private static extern bool OpenClipboard(IntPtr hWndNewOwner); 60 | 61 | [DllImport("user32.dll")] 62 | [return: MarshalAs(UnmanagedType.Bool)] 63 | private static extern bool CloseClipboard(); 64 | 65 | [DllImport("user32.dll")] 66 | private static extern IntPtr SetClipboardData(uint uFormat, IntPtr data); 67 | 68 | public enum ResultCode 69 | { 70 | Success = 0, 71 | 72 | ErrorOpenClipboard = 1, 73 | ErrorGlobalAlloc = 2, 74 | ErrorGlobalLock = 3, 75 | ErrorSetClipboardData = 4, 76 | ErrorOutOfMemoryException = 5, 77 | ErrorArgumentOutOfRangeException = 6, 78 | ErrorException = 7, 79 | ErrorInvalidArgs = 8, 80 | ErrorGetLastError = 9 81 | }; 82 | 83 | public class Result 84 | { 85 | public ResultCode ResultCode { get; set; } 86 | 87 | public uint LastError { get; set; } 88 | 89 | public bool OK { 90 | // ReSharper disable once RedundantNameQualifier 91 | get { return Clippy.ResultCode.Success == ResultCode; } 92 | } 93 | } 94 | 95 | [STAThread] 96 | public static Result PushStringToClipboard(string message) 97 | { 98 | var isAscii = (message != null && (message == Encoding.ASCII.GetString(Encoding.ASCII.GetBytes(message)))); 99 | if (isAscii) 100 | { 101 | return PushUnicodeStringToClipboard(message); 102 | } 103 | else 104 | { 105 | return PushAnsiStringToClipboard(message); 106 | } 107 | } 108 | 109 | [STAThread] 110 | public static Result PushUnicodeStringToClipboard(string message) 111 | { 112 | return __PushStringToClipboard(message, CF_UNICODETEXT); 113 | } 114 | 115 | [STAThread] 116 | public static Result PushAnsiStringToClipboard(string message) 117 | { 118 | return __PushStringToClipboard(message, CF_TEXT); 119 | } 120 | 121 | // ReSharper disable InconsistentNaming 122 | const uint CF_TEXT = 1; 123 | const uint CF_UNICODETEXT = 13; 124 | // ReSharper restore InconsistentNaming 125 | 126 | [STAThread] 127 | private static Result __PushStringToClipboard(string message, uint format) 128 | { 129 | try 130 | { 131 | try 132 | { 133 | if (message == null) 134 | { 135 | return new Result {ResultCode = ResultCode.ErrorInvalidArgs }; 136 | } 137 | 138 | if (!OpenClipboard(IntPtr.Zero)) 139 | { 140 | return new Result { ResultCode = ResultCode.ErrorOpenClipboard, LastError = GetLastError() }; 141 | } 142 | 143 | try 144 | { 145 | uint sizeOfChar; 146 | switch (format) 147 | { 148 | case CF_TEXT: 149 | sizeOfChar = 1; 150 | break; 151 | case CF_UNICODETEXT: 152 | sizeOfChar = 2; 153 | break; 154 | default: 155 | throw new Exception("Not Reachable"); 156 | } 157 | 158 | var characters = (uint)message.Length; 159 | uint bytes = (characters + 1) * sizeOfChar; 160 | 161 | // ReSharper disable once InconsistentNaming 162 | const int GMEM_MOVABLE = 0x0002; 163 | // ReSharper disable once InconsistentNaming 164 | const int GMEM_ZEROINIT = 0x0040; 165 | // ReSharper disable once InconsistentNaming 166 | const int GHND = GMEM_MOVABLE | GMEM_ZEROINIT; 167 | 168 | // IMPORTANT: SetClipboardData requires memory that was acquired with GlobalAlloc using GMEM_MOVABLE. 169 | var hGlobal = GlobalAlloc(GHND, (UIntPtr) bytes); 170 | if (hGlobal == IntPtr.Zero) 171 | { 172 | return new Result { ResultCode = ResultCode.ErrorGlobalAlloc, LastError = GetLastError() }; 173 | } 174 | 175 | try 176 | { 177 | // IMPORTANT: Marshal.StringToHGlobalUni allocates using LocalAlloc with LMEM_FIXED. 178 | // Note that LMEM_FIXED implies that LocalLock / LocalUnlock is not required. 179 | IntPtr source; 180 | switch (format) 181 | { 182 | case CF_TEXT: 183 | source = Marshal.StringToHGlobalAnsi(message); 184 | break; 185 | case CF_UNICODETEXT: 186 | source = Marshal.StringToHGlobalUni(message); 187 | break; 188 | default: 189 | throw new Exception("Not Reachable"); 190 | } 191 | 192 | try 193 | { 194 | var target = GlobalLock(hGlobal); 195 | if (target == IntPtr.Zero) 196 | { 197 | return new Result { ResultCode = ResultCode.ErrorGlobalLock, LastError = GetLastError() }; 198 | } 199 | 200 | try 201 | { 202 | CopyMemory(target, source, bytes); 203 | } 204 | finally 205 | { 206 | var ignore = GlobalUnlock(target); 207 | } 208 | 209 | if (SetClipboardData(format, hGlobal).ToInt64() != 0) 210 | { 211 | // IMPORTANT: SetClipboardData takes ownership of hGlobal upon success. 212 | hGlobal = IntPtr.Zero; 213 | } 214 | else 215 | { 216 | return new Result { ResultCode = ResultCode.ErrorSetClipboardData, LastError = GetLastError() }; 217 | } 218 | } 219 | finally 220 | { 221 | // Marshal.StringToHGlobalUni actually allocates with LocalAlloc, thus we should theorhetically use LocalFree to free the memory... 222 | // ... but Marshal.FreeHGlobal actully uses a corresponding version of LocalFree internally, so this works, even though it doesn't 223 | // behave exactly as expected. 224 | Marshal.FreeHGlobal(source); 225 | } 226 | } 227 | catch (OutOfMemoryException) 228 | { 229 | return new Result { ResultCode = ResultCode.ErrorOutOfMemoryException, LastError = GetLastError() }; 230 | } 231 | catch (ArgumentOutOfRangeException) 232 | { 233 | return new Result { ResultCode = ResultCode.ErrorArgumentOutOfRangeException, LastError = GetLastError() }; 234 | } 235 | finally 236 | { 237 | if (hGlobal != IntPtr.Zero) 238 | { 239 | var ignore = GlobalFree(hGlobal); 240 | } 241 | } 242 | } 243 | finally 244 | { 245 | CloseClipboard(); 246 | } 247 | return new Result { ResultCode = ResultCode.Success }; 248 | } 249 | catch (Exception) 250 | { 251 | return new Result { ResultCode = ResultCode.ErrorException, LastError = GetLastError() }; 252 | } 253 | } 254 | catch (Exception) 255 | { 256 | return new Result { ResultCode = ResultCode.ErrorGetLastError }; 257 | } 258 | } 259 | } 260 | } -------------------------------------------------------------------------------- /Clippy/Clippy.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B6B651B1-13E1-4682-A303-CD0EB1BB41AF} 8 | Library 9 | Properties 10 | Clippy 11 | Clippy 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 53 | -------------------------------------------------------------------------------- /Clippy/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Clippy")] 8 | [assembly: AssemblyDescription("Manipulate the clipboard without using Windows.Forms")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Kolibri")] 11 | [assembly: AssemblyProduct("Clippy")] 12 | [assembly: AssemblyCopyright("Copyright © 2014 Kolibri")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("b631b2e4-b0c8-45dd-9a14-ff9c0c858518")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ClippyTest/BasicUsage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Windows.Forms; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Kolibri; 6 | 7 | namespace ClippyTest 8 | { 9 | [TestClass] 10 | public class BasicUsage 11 | { 12 | [TestInitialize] 13 | public void Setup() 14 | { 15 | Clipboard.Clear(); 16 | } 17 | 18 | private static readonly string[] clipboardDataFormats = 19 | { 20 | DataFormats.Bitmap, 21 | DataFormats.CommaSeparatedValue, 22 | DataFormats.Dib, 23 | DataFormats.Dif, 24 | DataFormats.EnhancedMetafile, 25 | DataFormats.FileDrop, 26 | DataFormats.Html, 27 | DataFormats.Locale, 28 | DataFormats.MetafilePict, 29 | DataFormats.OemText, 30 | DataFormats.Palette, 31 | DataFormats.PenData, 32 | DataFormats.Riff, 33 | DataFormats.Rtf, 34 | DataFormats.Serializable, 35 | DataFormats.StringFormat, 36 | DataFormats.SymbolicLink, 37 | DataFormats.Text, 38 | DataFormats.Tiff, 39 | DataFormats.UnicodeText, 40 | DataFormats.WaveAudio 41 | }; 42 | 43 | private static bool IsClipboardNonEmpty() 44 | { 45 | return clipboardDataFormats.Any(Clipboard.ContainsData); 46 | } 47 | 48 | private static bool IsClipboardEmpty() 49 | { 50 | return !IsClipboardNonEmpty(); 51 | } 52 | 53 | [TestMethod] 54 | public void PushNullStringToClipboardIsntAllowed() 55 | { 56 | var result = Clippy.PushStringToClipboard(null); 57 | Assert.IsNotNull(result); 58 | Assert.AreEqual(Clippy.ResultCode.ErrorInvalidArgs, result.ResultCode); 59 | Assert.IsTrue(IsClipboardEmpty()); 60 | } 61 | 62 | [TestMethod] 63 | public void PushAsciiStringToClipboardWillBeAscii() 64 | { 65 | var p = "asdf"; 66 | var result = Clippy.PushStringToClipboard(p); 67 | Assert.IsNotNull(result); 68 | Assert.IsTrue(result.OK); 69 | Assert.IsTrue(Clipboard.ContainsData(DataFormats.Text)); 70 | Assert.IsTrue(Clipboard.GetText() == p); 71 | } 72 | 73 | [TestMethod] 74 | public void PushNonAsciiStringToClipboardWillBeUnicode() 75 | { 76 | var p = "áéíóúýðæö"; 77 | var result = Clippy.PushStringToClipboard(p); 78 | Assert.IsNotNull(result); 79 | Assert.IsTrue(result.OK); 80 | Assert.IsTrue(Clipboard.ContainsData(DataFormats.UnicodeText)); 81 | Assert.IsTrue(Clipboard.GetText() == p); 82 | } 83 | 84 | [TestMethod] 85 | public void PushEmptyStringToClipboardDoesntBomb() 86 | { 87 | const string p = ""; 88 | var result = Clippy.PushStringToClipboard(p); 89 | Assert.IsNotNull(result); 90 | Assert.IsTrue(result.OK); 91 | Assert.IsTrue(Clipboard.ContainsData(DataFormats.UnicodeText)); 92 | Assert.IsTrue(Clipboard.GetText() == p); 93 | } 94 | 95 | [TestMethod] 96 | public void PushAnyStringToClipboardDoesntBomb() 97 | { 98 | const string p = "Clippy!"; 99 | var result = Clippy.PushStringToClipboard(p); 100 | Assert.IsNotNull(result); 101 | Assert.IsTrue(result.OK); 102 | Assert.IsFalse(IsClipboardEmpty()); 103 | Assert.IsTrue(Clipboard.ContainsData(DataFormats.UnicodeText)); 104 | Assert.IsTrue(Clipboard.GetText() == p); 105 | } 106 | 107 | private enum WindowsErrorCodes : uint 108 | { 109 | Success = 0, 110 | ErrorNotEnoughMemory = 8 111 | } 112 | 113 | [TestMethod] 114 | public void PushHugeStringToClipboardDoesntBomb() 115 | { 116 | var stuff = "1234567890"; 117 | for (var i = 0; i < 99; ++i) 118 | { 119 | var outOfMemory = false; 120 | try 121 | { 122 | stuff += stuff; 123 | } 124 | catch (OutOfMemoryException) 125 | { 126 | outOfMemory = true; 127 | } 128 | 129 | var result = Clippy.PushStringToClipboard(stuff); 130 | Assert.IsNotNull(result); 131 | switch (result.ResultCode) 132 | { 133 | case Clippy.ResultCode.Success: 134 | break; 135 | case Clippy.ResultCode.ErrorGlobalAlloc: 136 | Assert.AreEqual(WindowsErrorCodes.ErrorNotEnoughMemory, (WindowsErrorCodes)result.LastError); 137 | Assert.IsFalse(Clipboard.GetText() == stuff); 138 | break; 139 | case Clippy.ResultCode.ErrorOutOfMemoryException: 140 | Assert.AreEqual(WindowsErrorCodes.Success, (WindowsErrorCodes)result.LastError); 141 | Assert.IsFalse(Clipboard.GetText() == stuff); 142 | break; 143 | default: 144 | Assert.Fail("Unexpected result code ({0}) and windows error ({1})", result.ResultCode, result.LastError); 145 | break; 146 | } 147 | 148 | if (outOfMemory) 149 | { 150 | Assert.IsFalse(result.OK); 151 | } 152 | else 153 | { 154 | if (result.OK) 155 | { 156 | Assert.IsTrue(Clipboard.ContainsData(DataFormats.UnicodeText)); 157 | Assert.IsTrue(Clipboard.GetText() == stuff); 158 | } 159 | else 160 | { 161 | Assert.IsFalse(Clipboard.GetText() == stuff); 162 | return; 163 | } 164 | } 165 | } 166 | Assert.Inconclusive(); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /ClippyTest/ClippyTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {F9B4726F-C7D5-4DDE-AF86-7DA246FF1F5A} 7 | Library 8 | Properties 9 | ClippyTest 10 | ClippyTest 11 | v4.5 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {b6b651b1-13e1-4682-a303-cd0eb1bb41af} 60 | Clippy 61 | 62 | 63 | 64 | 65 | 66 | 67 | False 68 | 69 | 70 | False 71 | 72 | 73 | False 74 | 75 | 76 | False 77 | 78 | 79 | 80 | 81 | 82 | 83 | 90 | -------------------------------------------------------------------------------- /ClippyTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ClippyTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ClippyTest")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4fc43340-31ad-4a91-b70e-784a0a9f233a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Kolibri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | clippy 2 | ====== 3 | 4 | Push a string to the Windows clipboard, without the Windows Forms assembly 5 | -------------------------------------------------------------------------------- /Sample/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using Kolibri; 2 | 3 | namespace Sample 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | if (args.Length > 0) 10 | { 11 | Clippy.PushStringToClipboard(args[0]); 12 | System.Console.WriteLine("pushed \"{0}\" to the clipboard.",args[0]); 13 | } 14 | else 15 | { 16 | System.Console.WriteLine("usage: sample.exe \"\""); 17 | System.Console.WriteLine(" pushes the message onto the clipboard."); 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Clippy Sample")] 8 | [assembly: AssemblyDescription("Sample application for Clippy. Pushes a string to the clipboard.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Kolibri")] 11 | [assembly: AssemblyProduct("Clippy")] 12 | [assembly: AssemblyCopyright("Copyright © Kolibri 2014")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("25a09c91-7521-417f-9cab-756b854b068d")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Sample/Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FE964C0A-C17B-476E-9906-DD12CC3C772F} 8 | Exe 9 | Properties 10 | Sample 11 | Sample 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {b6b651b1-13e1-4682-a303-cd0eb1bb41af} 53 | Clippy 54 | 55 | 56 | 57 | 64 | --------------------------------------------------------------------------------