/// <summary> /// Get a list of filenames on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboard</param> /// <returns>IEnumerable of string</returns> public static IEnumerable <string> GetFilenames(this IClipboardAccessToken clipboardAccessToken) { clipboardAccessToken.ThrowWhenNoAccess(); var hDrop = NativeMethods.GetClipboardData((uint)StandardClipboardFormats.Drop); unsafe { var files = NativeMethods.DragQueryFile(hDrop, uint.MaxValue, null, 0); if (files == 0) { return(Enumerable.Empty <string>()); } var result = new List <string>(); const int capacity = 260; var filename = stackalloc char[capacity]; for (uint i = 0; i < files; i++) { var nrCharacters = NativeMethods.DragQueryFile(hDrop, i, filename, capacity); if (nrCharacters == 0) { continue; } result.Add(new string(filename, 0, nrCharacters)); } return(result); } }
/// <summary> /// Create ClipboardNativeInfo to read /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="formatId">uint</param> /// <returns>ClipboardNativeInfo</returns> public static ClipboardNativeInfo ReadInfo(this IClipboardAccessToken clipboardAccessToken, uint formatId) { clipboardAccessToken.ThrowWhenNoAccess(); var hGlobal = NativeMethods.GetClipboardData(formatId); if (hGlobal == IntPtr.Zero) { if (NativeMethods.IsClipboardFormatAvailable(formatId)) { throw new Win32Exception($"Format {formatId} not available."); } throw new Win32Exception(); } var memoryPtr = Kernel32Api.GlobalLock(hGlobal); if (memoryPtr == IntPtr.Zero) { throw new Win32Exception(); } return(new ClipboardNativeInfo { GlobalHandle = hGlobal, MemoryPtr = memoryPtr, FormatId = formatId }); }
/// <summary> /// Factory for the write information /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="formatId">uint with the format id</param> /// <param name="size">int with the size of the clipboard area</param> /// <returns>ClipboardNativeInfo</returns> public static ClipboardNativeInfo WriteInfo(this IClipboardAccessToken clipboardAccessToken, uint formatId, long size) { clipboardAccessToken.ThrowWhenNoAccess(); var hGlobal = Kernel32Api.GlobalAlloc(GlobalMemorySettings.ZeroInit | GlobalMemorySettings.Movable, new UIntPtr((ulong)size)); if (hGlobal == IntPtr.Zero) { throw new Win32Exception(); } var memoryPtr = Kernel32Api.GlobalLock(hGlobal); if (memoryPtr == IntPtr.Zero) { throw new Win32Exception(); } return(new ClipboardNativeInfo { GlobalHandle = hGlobal, MemoryPtr = memoryPtr, NeedsWrite = true, FormatId = formatId }); }
/// <summary> /// Place byte[] on the clipboard, this assumes you already locked the clipboard. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="bytes">bytes to place on the clipboard</param> /// <param name="formatId">uint with the format ID to place the bytes under</param> public static void SetAsBytes(this IClipboardAccessToken clipboardAccessToken, byte[] bytes, uint formatId) { using var writeInfo = clipboardAccessToken.WriteInfo(formatId, bytes.Length); unsafe { using var unsafeMemoryStream = new UnmanagedMemoryStream((byte *)writeInfo.MemoryPtr, bytes.Length, bytes.Length, FileAccess.Write); unsafeMemoryStream.Write(bytes, 0, bytes.Length); } }
/// <summary> /// Retrieve the content for the specified format. /// You will need to "lock" (OpenClipboard) the clipboard before calling this. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="formatId">uint with the format to retrieve the content for</param> /// <returns>byte array</returns> public static byte[] GetAsBytes(this IClipboardAccessToken clipboardAccessToken, uint formatId) { using var readInfo = clipboardAccessToken.ReadInfo(formatId); var bytes = new byte[readInfo.Size]; // Fill the memory stream Marshal.Copy(readInfo.MemoryPtr, bytes, 0, readInfo.Size); return(bytes); }
/// <summary> /// Place the bitmap as HTML on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="surface">ISurface</param> public static void SetAsHtml(this IClipboardAccessToken clipboardAccessToken, ISurface surface) { var pngOutputSettings = new SurfaceOutputSettings(OutputFormats.png, 100, false); // This file is automatically deleted when Greenshot exits. var filename = ImageOutput.SaveNamedTmpFile(surface, surface.CaptureDetails, pngOutputSettings); // Set the PNG stream var htmlText = GenerateHtmlString(new NativeSize(surface.Width, surface.Height), filename); clipboardAccessToken.SetAsHtml(htmlText); }
/// <summary> /// Place HTML on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="htmlText">string with the html</param> public static void SetAsHtml(this IClipboardAccessToken clipboardAccessToken, string htmlText) { if (!_htmlFormatId.HasValue) { _htmlFormatId = ClipboardFormatExtensions.RegisterFormat(HtmlFormat); } // Set the Html stream clipboardAccessToken.SetAsUnicodeString(htmlText, _htmlFormatId.Value); }
/// <summary> /// Place Uri on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="url">string with the url</param> public static void SetAsUrl(this IClipboardAccessToken clipboardAccessToken, string url) { if (!_urlFormatId.HasValue) { _urlFormatId = ClipboardFormatExtensions.RegisterFormat(UrlFormat); } // Set the Html stream clipboardAccessToken.SetAsUnicodeString(url, _urlFormatId.Value); }
/// <summary> /// Place the bitmap on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="surface">ISurface</param> /// <param name="outputSettings">SurfaceOutputSettings specifying how to output the surface</param> public static void SetAsBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface, SurfaceOutputSettings outputSettings) { using (var bitmapStream = new MemoryStream()) { ImageOutput.SaveToStream(surface, bitmapStream, outputSettings); bitmapStream.Seek(0, SeekOrigin.Begin); // Set the stream var clipboardFormat = ClipboardFormatExtensions.MapFormatToId(outputSettings.Format.ToString().ToUpperInvariant()); clipboardAccessToken.SetAsStream(clipboardFormat, bitmapStream); } }
/// <summary> /// Place the bitmap as embedded HTML on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="surface">ISurface</param> public static void SetAsEmbeddedHtml(this IClipboardAccessToken clipboardAccessToken, ISurface surface) { using (var pngStream = new MemoryStream()) { var pngOutputSettings = new SurfaceOutputSettings(OutputFormats.png, 100, false); ImageOutput.SaveToStream(surface, pngStream, pngOutputSettings); pngStream.Seek(0, SeekOrigin.Begin); // Set the PNG stream var htmlText = GenerateHtmlDataUrlString(new NativeSize(surface.Width, surface.Height), pngStream); clipboardAccessToken.SetAsHtml(htmlText); } }
/// <summary> /// Place the bitmap on the clipboard as DIB /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="surface">ISurface</param> public static void SetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface) { using (var bitmapStream = new MemoryStream()) { ImageOutput.SaveToStream(surface, bitmapStream, new SurfaceOutputSettings { Format = OutputFormats.bmp }); bitmapStream.Seek(Marshal.SizeOf(typeof(BitmapFileHeader)), SeekOrigin.Begin); // Set the stream clipboardAccessToken.SetAsStream(StandardClipboardFormats.DeviceIndependentBitmap, bitmapStream); } }
/// <summary> /// Retrieve the content for the specified format. /// You will need to "lock" (OpenClipboard) the clipboard before calling this. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="formatId">uint with the format to retrieve the content for</param> /// <returns>MemoryStream</returns> public static Stream GetAsStream(this IClipboardAccessToken clipboardAccessToken, uint formatId) { var readInfo = clipboardAccessToken.ReadInfo(formatId); // return the memory stream, the global unlock is done when the UnmanagedMemoryStreamWrapper is disposed unsafe { var result = new UnmanagedMemoryStreamWrapper((byte *)readInfo.MemoryPtr, readInfo.Size, readInfo.Size, FileAccess.Read); // Make sure the readinfo is disposed when needed result.SetDisposable(readInfo); return(result); } }
/// <summary> /// Is there a Bitmap on the clipboard? /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <returns>bool</returns> public static bool HasImage(this IClipboardAccessToken clipboardAccessToken) { var formats = clipboardAccessToken.AvailableFormats(); if (formats.Intersect(SupportedBitmapFormats).Any()) { return(true); } return(clipboardAccessToken.GetFilenames() .Select(filename => Path.GetExtension(filename).ToLowerInvariant()) .Intersect(SupportedExtensions) .Any()); }
/// <summary> /// Set the content for the specified format. /// You will need to "lock" (OpenClipboard) the clipboard before calling this. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="formatId">uint with the format to set the content for</param> /// <param name="stream">MemoryStream with the content</param> /// <param name="size">long with the size, if the stream is not seekable</param> public static void SetAsStream(this IClipboardAccessToken clipboardAccessToken, uint formatId, Stream stream, long?size = null) { clipboardAccessToken.ThrowWhenNoAccess(); if (!stream.CanRead) { throw new NotSupportedException("Can't read stream"); } // The following decides how to calculate the size bool needsDispose = false; long length; if (stream.CanSeek) { // Calculate the rest left length = stream.Length - stream.Position; if (length <= 0) { throw new NotSupportedException($"Cannot write {length} length stream."); } } else if (size.HasValue) { length = size.Value; } else { var bufferStream = new MemoryStream(); needsDispose = true; stream.CopyTo(bufferStream); length = bufferStream.Length; stream = bufferStream; } // Now "paste" unsafe { using (var writeInfo = clipboardAccessToken.WriteInfo(formatId, length)) using (var unsafeMemoryStream = new UnmanagedMemoryStream((byte *)writeInfo.MemoryPtr, length, length, FileAccess.Write)) { stream.CopyTo(unsafeMemoryStream); } if (needsDispose) { stream.Dispose(); } } }
/// <summary> /// A special format 17 bitmap reader /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <returns>Bitmap or null</returns> public static Bitmap GetAsFormat17(this IClipboardAccessToken clipboardAccessToken) { var formats = clipboardAccessToken.AvailableFormats().ToList(); if (!formats.Contains("Format17")) { return(null); } var format17Bytes = clipboardAccessToken.GetAsBytes("Format17"); var infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(format17Bytes); if (!infoHeader.IsDibV5) { return(null); } // Using special DIBV5 / Format17 format reader // CF_DIBV5 var gcHandle = IntPtr.Zero; try { var handle = GCHandle.Alloc(format17Bytes, GCHandleType.Pinned); gcHandle = GCHandle.ToIntPtr(handle); return (new Bitmap(infoHeader.Width, infoHeader.Height, -(int)(infoHeader.SizeImage / infoHeader.Height), infoHeader.BitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb, new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.Height - 1) * (int)(infoHeader.SizeImage / infoHeader.Height)) )); } catch (Exception ex) { Log.Error().WriteLine(ex, "Problem retrieving Format17 from clipboard."); } finally { if (gcHandle == IntPtr.Zero) { GCHandle.FromIntPtr(gcHandle).Free(); } } return(null); }
/// <summary> /// Place the surface as Format17 bitmap on the clipboard /// </summary> /// <param name="clipboardAccessToken">IClipboardAccessToken</param> /// <param name="surface">ISurface</param> public static void SetAsFormat17(this IClipboardAccessToken clipboardAccessToken, ISurface surface) { // Create the stream for the clipboard using (var dibV5Stream = new MemoryStream()) { var outputSettings = new SurfaceOutputSettings(OutputFormats.bmp, 100, false); bool dispose = ImageOutput.CreateBitmapFromSurface(surface, outputSettings, out var bitmapToSave); // Create the BITMAPINFOHEADER var header = BitmapInfoHeader.Create(bitmapToSave.Width, bitmapToSave.Height, 32); // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? header.Compression = BitmapCompressionMethods.BI_BITFIELDS; var headerBytes = BinaryStructHelper.ToByteArray(header); // Write the BITMAPINFOHEADER to the stream dibV5Stream.Write(headerBytes, 0, headerBytes.Length); // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added var colorMask = BitfieldColorMask.Create(); // Create the byte[] from the struct var colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); Array.Reverse(colorMaskBytes); // Write to the stream dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); // Create the raw bytes for the pixels only var bitmapBytes = BitmapToByteArray(bitmapToSave); // Write to the stream dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); // Reset the stream to the beginning so it can be written dibV5Stream.Seek(0, SeekOrigin.Begin); // Set the DIBv5 to the clipboard DataObject clipboardAccessToken.SetAsStream("Format17", dibV5Stream); if (dispose) { bitmapToSave.Dispose(); } } }
/// <summary> /// Enumerate through all formats on the clipboard, assumes the clipboard was already locked. /// </summary> /// <returns>IEnumerable with strings defining the format</returns> public static IEnumerable <uint> AvailableFormatIds(this IClipboardAccessToken clipboardAccessToken) { clipboardAccessToken.ThrowWhenNoAccess(); uint clipboardFormatId = 0; while (true) { clipboardFormatId = NativeMethods.EnumClipboardFormats(clipboardFormatId); if (clipboardFormatId == 0) { // If GetLastWin32Error return SuccessError, this is the end if (Marshal.GetLastWin32Error() == SuccessError) { yield break; } // GetLastWin32Error didn't return SuccessError, so throw exception throw new Win32Exception(); } yield return(clipboardFormatId); } }
/// <summary> /// Get a DIB from the Clipboard /// </summary> /// <param name="clipboardAccessToken"></param> /// <returns>Bitmap or null</returns> public static Bitmap GetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken) { var formats = clipboardAccessToken.AvailableFormats().ToList(); if (!formats.Contains(StandardClipboardFormats.Bitmap.AsString())) { return(null); } var format17Bytes = clipboardAccessToken.GetAsBytes(StandardClipboardFormats.Bitmap.AsString()); var infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(format17Bytes); if (infoHeader.IsDibV5) { Log.Warn().WriteLine("Getting DIBV5 (format 17) when requesting DIB"); return(null); } // Bitmap version older than 5 var fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader)); var fileHeader = BitmapFileHeader.Create(infoHeader); var fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader); using (var bitmapStream = new MemoryStream()) { bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(format17Bytes, 0, format17Bytes.Length); bitmapStream.Seek(0, SeekOrigin.Begin); var image = BitmapHelper.FromStream(bitmapStream); if (image != null) { return(image); } } return(null); }
/// <summary> /// Place byte[] on the clipboard, this assumes you already locked the clipboard. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="bytes">bytes to place on the clipboard</param> /// <param name="format">string with the format to place the bytes under</param> public static void SetAsBytes(this IClipboardAccessToken clipboardAccessToken, byte[] bytes, string format) { clipboardAccessToken.SetAsBytes(bytes, ClipboardFormatExtensions.MapFormatToId(format)); }
/// <summary> /// Place byte[] on the clipboard, this assumes you already locked the clipboard. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="bytes">bytes to place on the clipboard</param> /// <param name="format">StandardClipboardFormats with format to place the bytes under</param> public static void SetAsBytes(this IClipboardAccessToken clipboardAccessToken, byte[] bytes, StandardClipboardFormats format) { clipboardAccessToken.SetAsBytes(bytes, (uint)format); }
/// <summary> /// Retrieve the content for the specified format. /// You will need to "lock" (OpenClipboard) the clipboard before calling this. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="format">string with the format to retrieve the content for</param> /// <returns>byte array</returns> public static byte[] GetAsBytes(this IClipboardAccessToken clipboardAccessToken, string format) { return(clipboardAccessToken.GetAsBytes(ClipboardFormatExtensions.MapFormatToId(format))); }
/// <summary> /// Retrieve the content for the specified format. /// You will need to "lock" (OpenClipboard) the clipboard before calling this. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="format">StandardClipboardFormats with the format to retrieve the content for</param> /// <returns>byte array</returns> public static byte[] GetAsBytes(this IClipboardAccessToken clipboardAccessToken, StandardClipboardFormats format) { return(clipboardAccessToken.GetAsBytes((uint)format)); }
/// <summary> /// Get a string from the clipboard, this assumes you already locked the clipboard. /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="format">StandardClipboardFormats with the clipboard format</param> /// <returns>string</returns> public static string GetAsUnicodeString(this IClipboardAccessToken clipboardAccessToken, StandardClipboardFormats format) { return(clipboardAccessToken.GetAsUnicodeString((uint)format)); }
/// <summary> /// Get a string from the clipboard, this assumes you already locked the clipboard. /// This always takes the CF_UNICODETEXT format, as Windows automatically converts /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="format">string with the clipboard format</param> /// <returns>string</returns> public static string GetAsUnicodeString(this IClipboardAccessToken clipboardAccessToken, string format) { return(clipboardAccessToken.GetAsUnicodeString(ClipboardFormatExtensions.MapFormatToId(format))); }
/// <summary> /// This class can only be instantiated when there is a clipboard lock, that is why the constructor is private. /// </summary> private ClipboardUpdateInformation(IClipboardAccessToken clipboardAccessToken) { FormatIds = clipboardAccessToken.AvailableFormatIds().ToList(); }
/// <summary> /// This places delayed rendered content on the clipboard /// </summary> /// <param name="clipboardAccessToken">The IClipboardAccessToken</param> /// <param name="formatId">uint with the clipboard format</param> public static void SetDelayedRenderedContent(this IClipboardAccessToken clipboardAccessToken, uint formatId) { clipboardAccessToken.ThrowWhenNoAccess(); NativeMethods.SetClipboardDataWithErrorHandling(formatId, IntPtr.Zero); }
/// <summary> /// This places delayed rendered content on the clipboard, don't forget to subscribe to ClipboardNative.OnRenderFormat /// </summary> /// <param name="clipboardAccessToken">The IClipboardAccessToken</param> /// <param name="format">string with the clipboard format</param> public static void SetDelayedRenderedContent(this IClipboardAccessToken clipboardAccessToken, string format) { SetDelayedRenderedContent(clipboardAccessToken, ClipboardFormatExtensions.MapFormatToId(format)); }
/// <summary> /// This places delayed rendered content on the clipboard /// </summary> /// <param name="clipboardAccessToken">The IClipboardAccessToken</param> /// <param name="format">StandardClipboardFormats with the clipboard format</param> public static void SetDelayedRenderedContent(this IClipboardAccessToken clipboardAccessToken, StandardClipboardFormats format) { SetDelayedRenderedContent(clipboardAccessToken, (uint)format); }
/// <summary> /// Empties the clipboard, this assumes that a lock has already been retrieved. /// </summary> public static void ClearContents(this IClipboardAccessToken clipboardAccessToken) { clipboardAccessToken.ThrowWhenNoAccess(); NativeMethods.EmptyClipboard(); }
/// <summary> /// Get a string from the clipboard, this assumes you already locked the clipboard. /// This by default takes the CF_UNICODETEXT format, as Windows automatically converts /// </summary> /// <param name="clipboardAccessToken">IClipboardLock</param> /// <param name="formatId">uint with the clipboard format</param> /// <returns>string</returns> public static string GetAsUnicodeString(this IClipboardAccessToken clipboardAccessToken, uint formatId = (uint)StandardClipboardFormats.UnicodeText) { var bytes = clipboardAccessToken.GetAsBytes(formatId); return(Encoding.Unicode.GetString(bytes, 0, bytes.Length).TrimEnd('\0')); }