/// <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);
            }
        }
Пример #2
0
        /// <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
            });
        }
Пример #3
0
        /// <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
            });
        }
Пример #4
0
 /// <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);
     }
 }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        /// <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);
     }
 }
Пример #10
0
 /// <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);
     }
 }
Пример #12
0
        /// <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());
        }
Пример #14
0
        /// <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));
 }
Пример #23
0
 /// <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));
 }
Пример #24
0
 /// <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)));
 }
Пример #25
0
 /// <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();
 }
Пример #30
0
        /// <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'));
        }