From 4fd9fa5cbeabf7e00a348b1bc8a0323690be2b8f Mon Sep 17 00:00:00 2001 From: Afonin Dmitry Date: Wed, 17 Jan 2018 14:42:43 +0500 Subject: [PATCH 1/4] Clipboard functions were added. #15 --- Samples/Sample.SimpleWindow/Program.cs | 12 +++-- Samples/Sample.Win32/Program.cs | 9 ++++ WinApi/User32/Constants.cs | 20 ++++++++ WinApi/User32/Helpers.cs | 65 ++++++++++++++++++++++++++ WinApi/User32/Methods.cs | 58 +++++++++++++++++++++++ 5 files changed, 160 insertions(+), 4 deletions(-) diff --git a/Samples/Sample.SimpleWindow/Program.cs b/Samples/Sample.SimpleWindow/Program.cs index cb2406f..7c884e4 100644 --- a/Samples/Sample.SimpleWindow/Program.cs +++ b/Samples/Sample.SimpleWindow/Program.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinApi.Gdi32; using WinApi.User32; using WinApi.Windows; @@ -16,6 +12,7 @@ static int Main(string[] args) { using (var win = Window.Create("Hello")) { + User32Methods.AddClipboardFormatListener(win.Handle); win.Show(); return new EventLoop().Run(win); } @@ -62,6 +59,13 @@ protected override void OnMessage(ref WindowMessage msg) msg.Result = new IntPtr(1); return; } + case WM.CLIPBOARDUPDATE: + { + var text = User32Helpers.GetUnicodeTextFromClipboard(); + User32Helpers.MessageBox(text, "You've just copied something"); + break; + } + } base.OnMessage(ref msg); } diff --git a/Samples/Sample.Win32/Program.cs b/Samples/Sample.Win32/Program.cs index 8797b37..83fadbd 100644 --- a/Samples/Sample.Win32/Program.cs +++ b/Samples/Sample.Win32/Program.cs @@ -50,6 +50,8 @@ static int Main(string[] args) User32Methods.ShowWindow(hwnd, ShowWindowCommands.SW_SHOWNORMAL); User32Methods.UpdateWindow(hwnd); + User32Methods.AddClipboardFormatListener(hwnd); + Message msg; int res; while ((res = User32Methods.GetMessage(out msg, IntPtr.Zero, 0, 0)) != 0) @@ -83,6 +85,13 @@ private static IntPtr WindowProc(IntPtr hwnd, uint umsg, User32Methods.EndPaint(hwnd, ref ps); break; } + case WM.CLIPBOARDUPDATE: + { + var text = User32Helpers.GetUnicodeTextFromClipboard(); + User32Helpers.MessageBox(text, "You've just copied something"); + break; + } + } return User32Methods.DefWindowProc(hwnd, umsg, wParam, lParam); } diff --git a/WinApi/User32/Constants.cs b/WinApi/User32/Constants.cs index beb376e..2f5e101 100644 --- a/WinApi/User32/Constants.cs +++ b/WinApi/User32/Constants.cs @@ -5230,5 +5230,25 @@ public enum WM USER = 0x0400 } + public enum ClipboardFormat : uint + { + /// + /// A handle to a bitmap (HBITMAP) + /// + CF_BITMAP = 2u, + /// + /// Flag for text-format + /// + CF_TEXT = 1u, + /// + /// Flag for unicode-text-format + /// + CF_UNICODETEXT = 13u, + + /// + /// no format + /// + CF_ZERO = 0u + } #endregion } \ No newline at end of file diff --git a/WinApi/User32/Helpers.cs b/WinApi/User32/Helpers.cs index 2b46a36..89101d4 100644 --- a/WinApi/User32/Helpers.cs +++ b/WinApi/User32/Helpers.cs @@ -1,6 +1,13 @@ using System; +using System.Collections; +using System.IO; +using System.Linq; using System.Runtime.InteropServices; +using System.Text; +using NetCoreEx.BinaryExtensions; using NetCoreEx.Geometry; +using WinApi.Gdi32; +using WinApi.Kernel32; namespace WinApi.User32 { @@ -213,5 +220,63 @@ public static bool InverseAdjustWindowRectEx( if (res) Rectangle.Subtract(ref lpRect, ref rc); return res; } + + public static void PasteTextToClipboard(byte[] data) + { + if (User32Methods.OpenClipboard(new IntPtr())) + { + var bytesLength = data.Length; + var allocatedMemory = Marshal.AllocHGlobal(bytesLength); + try + { + Marshal.Copy(data, 0, allocatedMemory, bytesLength); + + var result = User32Methods.SetClipboardData((uint)ClipboardFormat.CF_TEXT, allocatedMemory); + + if (result == IntPtr.Zero) + throw new Exception(Kernel32Methods.GetLastError().ToString()); + } + finally + { + Marshal.FreeHGlobal(allocatedMemory); + } + } + User32Methods.CloseClipboard(); + + } + + public static unsafe string GetUnicodeTextFromClipboard() + { + var outString = default(string); + if (User32Methods.OpenClipboard(new IntPtr())) + { + var data = (char*)User32Methods.GetClipboardData((uint) ClipboardFormat.CF_UNICODETEXT); + outString = new string(data); + } + User32Methods.CloseClipboard(); + return outString; + } + + public static unsafe string GetTextFromClipboard() + { + var outString = default(string); + if (User32Methods.OpenClipboard(new IntPtr())) + { + var data = (char*)User32Methods.GetClipboardData((uint)ClipboardFormat.CF_TEXT); + outString = new string(data); + } + User32Methods.CloseClipboard(); + return outString; + } + + public static unsafe ClipboardFormat GetPriorityClipboardFormat(ClipboardFormat[] format) + { + fixed (ClipboardFormat* first = &format[0]) + { + var result = User32Methods.GetPriorityClipboardFormat((IntPtr) first, format.Length); + + return result >= 0 ? (ClipboardFormat) result : ClipboardFormat.CF_ZERO; + } + } } } \ No newline at end of file diff --git a/WinApi/User32/Methods.cs b/WinApi/User32/Methods.cs index 5b1e535..44ae342 100644 --- a/WinApi/User32/Methods.cs +++ b/WinApi/User32/Methods.cs @@ -820,5 +820,63 @@ public static extern int GetMessage(out Message lpMsg, IntPtr hwnd, uint wMsgFil public static extern bool PostThreadMessage(uint threadId, uint msg, IntPtr wParam, IntPtr lParam); #endregion + + #region Clipboard Functions + + /// + /// Opens the clipboard for examination and prevents other applications from modifying the clipboard content. + /// + /// A handle to the window to be associated with the open clipboard. If this parameter is NULL, the open clipboard is associated with the current task. + /// If the function succeeds, the return value is nonzero. + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern bool OpenClipboard(IntPtr hWndNewOwner); + /// + /// Closes the clipboard. + /// + /// If the function succeeds, the return value is nonzero. + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern bool CloseClipboard(); + /// + /// Retrieves data from the clipboard in a specified format. The clipboard must have been opened previously. + /// + /// A clipboard format. + /// If the function succeeds, the return value is the handle to a clipboard object in the specified format. + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr GetClipboardData(uint uFormat); + + /// + /// Places data on the clipboard in a specified clipboard format. The window must be the current clipboard owner, and the application must have called the OpenClipboard function + /// + /// The clipboard format + /// A handle to the data in the specified format + /// If the function succeeds, the return value is the handle to the data. + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr SetClipboardData(uint uFormat, IntPtr handle); + + /// + /// Empties the clipboard and frees handles to data in the clipboard. The function then assigns ownership of the clipboard to the window that currently has the clipboard open. + /// + /// + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern bool EmptyClipboard(); + + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer); + + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext); + + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AddClipboardFormatListener(IntPtr hwnd); + + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern int GetPriorityClipboardFormat(IntPtr paFormatPriorityList, int cFormats); + + [DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern uint EnumClipboardFormats(uint format); + + #endregion } } \ No newline at end of file From f3640b8591d2a144e371c10725ecc490fc443dee Mon Sep 17 00:00:00 2001 From: Afonin Dmitry Date: Wed, 23 May 2018 11:02:46 +0500 Subject: [PATCH 2/4] Clipboard helpers were fixed #15 --- Samples/Sample.SimpleWindow/Program.cs | 9 +- Samples/Sample.Win32/Program.cs | 7 +- WinApi/User32/Helpers.cs | 121 +++++++++++++++++-------- 3 files changed, 96 insertions(+), 41 deletions(-) diff --git a/Samples/Sample.SimpleWindow/Program.cs b/Samples/Sample.SimpleWindow/Program.cs index 7c884e4..20ef443 100644 --- a/Samples/Sample.SimpleWindow/Program.cs +++ b/Samples/Sample.SimpleWindow/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using WinApi.Gdi32; using WinApi.User32; using WinApi.Windows; @@ -13,6 +14,8 @@ static int Main(string[] args) using (var win = Window.Create("Hello")) { User32Methods.AddClipboardFormatListener(win.Handle); + User32Helpers.TrySetClipboardData(Encoding.Unicode.GetBytes("WOWSER"), ClipboardFormat.CF_UNICODETEXT); + win.Show(); return new EventLoop().Run(win); } @@ -61,8 +64,10 @@ protected override void OnMessage(ref WindowMessage msg) } case WM.CLIPBOARDUPDATE: { - var text = User32Helpers.GetUnicodeTextFromClipboard(); - User32Helpers.MessageBox(text, "You've just copied something"); + if (User32Helpers.TryGetUnicodeTextFromClipboard(out var text)) + User32Helpers.MessageBox(text, "You've just copied something"); + else + User32Helpers.MessageBox("This form can handle only the text-copy event"); break; } diff --git a/Samples/Sample.Win32/Program.cs b/Samples/Sample.Win32/Program.cs index 83fadbd..ffeeb5d 100644 --- a/Samples/Sample.Win32/Program.cs +++ b/Samples/Sample.Win32/Program.cs @@ -87,11 +87,12 @@ private static IntPtr WindowProc(IntPtr hwnd, uint umsg, } case WM.CLIPBOARDUPDATE: { - var text = User32Helpers.GetUnicodeTextFromClipboard(); - User32Helpers.MessageBox(text, "You've just copied something"); + if (User32Helpers.TryGetUnicodeTextFromClipboard(out var text)) + User32Helpers.MessageBox(text, "You've just copied something"); + else + User32Helpers.MessageBox("This form can handle only the text-copy event"); break; } - } return User32Methods.DefWindowProc(hwnd, umsg, wParam, lParam); } diff --git a/WinApi/User32/Helpers.cs b/WinApi/User32/Helpers.cs index 89101d4..0025f0c 100644 --- a/WinApi/User32/Helpers.cs +++ b/WinApi/User32/Helpers.cs @@ -221,62 +221,111 @@ public static bool InverseAdjustWindowRectEx( return res; } - public static void PasteTextToClipboard(byte[] data) + #region Clipboard helpers + + /// + /// Will try to set the specified data to the clipboard. + /// If it is a string keep in mind that string should be passed with a null-terminated character. + /// + /// The data to set + /// + /// + public static bool TrySetClipboardData(byte[] data, ClipboardFormat clipboardFormat) { - if (User32Methods.OpenClipboard(new IntPtr())) - { - var bytesLength = data.Length; - var allocatedMemory = Marshal.AllocHGlobal(bytesLength); - try - { - Marshal.Copy(data, 0, allocatedMemory, bytesLength); + if (!User32Methods.OpenClipboard(new IntPtr())) return false; - var result = User32Methods.SetClipboardData((uint)ClipboardFormat.CF_TEXT, allocatedMemory); + var bytesLength = data.Length; + var allocatedMemory = Marshal.AllocHGlobal(bytesLength); + + Marshal.Copy(data, 0, allocatedMemory, bytesLength); + + var result = User32Methods.SetClipboardData((uint)clipboardFormat, allocatedMemory); - if (result == IntPtr.Zero) - throw new Exception(Kernel32Methods.GetLastError().ToString()); - } - finally - { - Marshal.FreeHGlobal(allocatedMemory); - } - } User32Methods.CloseClipboard(); + //https://msdn.microsoft.com/en-us/library/windows/desktop/ms649051%28v=vs.85%29.aspx + // If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. + // The application may not write to or free the data once ownership has been transferred to the system, + //but it can lock and read from the data until the CloseClipboard function is called + + //The allocated memory should not be freed + + return result != IntPtr.Zero; } - public static unsafe string GetUnicodeTextFromClipboard() + /// + /// Will try to set the specified text to the clipboard + /// + /// The text to set + /// + public static bool TrySetClipboardUnicodeText(string textToSet) { - var outString = default(string); - if (User32Methods.OpenClipboard(new IntPtr())) - { - var data = (char*)User32Methods.GetClipboardData((uint) ClipboardFormat.CF_UNICODETEXT); - outString = new string(data); - } + if (!User32Methods.OpenClipboard(new IntPtr())) return false; + + var ptrToStr = Marshal.StringToHGlobalUni(textToSet); + + var result = User32Methods.SetClipboardData((uint)ClipboardFormat.CF_UNICODETEXT, ptrToStr); + User32Methods.CloseClipboard(); - return outString; + + //https://msdn.microsoft.com/en-us/library/windows/desktop/ms649051%28v=vs.85%29.aspx + // If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. + // The application may not write to or free the data once ownership has been transferred to the system, + //but it can lock and read from the data until the CloseClipboard function is called + + //The allocated memory should not be freed + + return result != IntPtr.Zero; } - public static unsafe string GetTextFromClipboard() + /// + /// Will try to get a unicode-string from the clipbard + /// + /// + /// + public static unsafe bool TryGetUnicodeTextFromClipboard(out string outString) { - var outString = default(string); - if (User32Methods.OpenClipboard(new IntPtr())) - { - var data = (char*)User32Methods.GetClipboardData((uint)ClipboardFormat.CF_TEXT); - outString = new string(data); - } + outString = string.Empty; + if (!User32Methods.OpenClipboard(new IntPtr())) return true; + + var ptrToData = User32Methods.GetClipboardData((uint)ClipboardFormat.CF_UNICODETEXT); User32Methods.CloseClipboard(); - return outString; + + if (ptrToData == IntPtr.Zero) + return false; + + outString = new string((char*)ptrToData); + + return true; } - public static unsafe ClipboardFormat GetPriorityClipboardFormat(ClipboardFormat[] format) + /// + /// Will try to retrieve the first available clipboard format. + /// + /// + /// + /// + public static unsafe bool TryGetPriorityClipboardFormat(ClipboardFormat[] format, out ClipboardFormat clipBoardFormat) { + clipBoardFormat = ClipboardFormat.CF_ZERO; fixed (ClipboardFormat* first = &format[0]) { - var result = User32Methods.GetPriorityClipboardFormat((IntPtr) first, format.Length); + var result = User32Methods.GetPriorityClipboardFormat((IntPtr)first, format.Length); - return result >= 0 ? (ClipboardFormat) result : ClipboardFormat.CF_ZERO; + //https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms649045(v=vs.85).aspx + switch (result) + { + case -1: + return false; + case 0: + return true; + default: + clipBoardFormat = (ClipboardFormat)result; + return true; + } } } + + #endregion } } \ No newline at end of file From bdc15518f8172d092c47b7bb5ac3f571edb05cdc Mon Sep 17 00:00:00 2001 From: Afonin Dmitry Date: Wed, 23 May 2018 14:09:36 +0500 Subject: [PATCH 3/4] TryGetUnicodeTextFromClipboard renamed into TryGetClipboardUnicodeText #15 --- Samples/Sample.SimpleWindow/Program.cs | 4 ++-- Samples/Sample.Win32/Program.cs | 2 +- WinApi/User32/Helpers.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Samples/Sample.SimpleWindow/Program.cs b/Samples/Sample.SimpleWindow/Program.cs index 20ef443..2137766 100644 --- a/Samples/Sample.SimpleWindow/Program.cs +++ b/Samples/Sample.SimpleWindow/Program.cs @@ -14,7 +14,7 @@ static int Main(string[] args) using (var win = Window.Create("Hello")) { User32Methods.AddClipboardFormatListener(win.Handle); - User32Helpers.TrySetClipboardData(Encoding.Unicode.GetBytes("WOWSER"), ClipboardFormat.CF_UNICODETEXT); + User32Helpers.TrySetClipboardData(Encoding.Unicode.GetBytes("WOWSER\0"), ClipboardFormat.CF_UNICODETEXT); win.Show(); return new EventLoop().Run(win); @@ -64,7 +64,7 @@ protected override void OnMessage(ref WindowMessage msg) } case WM.CLIPBOARDUPDATE: { - if (User32Helpers.TryGetUnicodeTextFromClipboard(out var text)) + if (User32Helpers.TryGetClipboardUnicodeText(out var text)) User32Helpers.MessageBox(text, "You've just copied something"); else User32Helpers.MessageBox("This form can handle only the text-copy event"); diff --git a/Samples/Sample.Win32/Program.cs b/Samples/Sample.Win32/Program.cs index ffeeb5d..ad813ca 100644 --- a/Samples/Sample.Win32/Program.cs +++ b/Samples/Sample.Win32/Program.cs @@ -87,7 +87,7 @@ private static IntPtr WindowProc(IntPtr hwnd, uint umsg, } case WM.CLIPBOARDUPDATE: { - if (User32Helpers.TryGetUnicodeTextFromClipboard(out var text)) + if (User32Helpers.TryGetClipboardUnicodeText(out var text)) User32Helpers.MessageBox(text, "You've just copied something"); else User32Helpers.MessageBox("This form can handle only the text-copy event"); diff --git a/WinApi/User32/Helpers.cs b/WinApi/User32/Helpers.cs index 0025f0c..9f218a9 100644 --- a/WinApi/User32/Helpers.cs +++ b/WinApi/User32/Helpers.cs @@ -283,7 +283,7 @@ public static bool TrySetClipboardUnicodeText(string textToSet) /// /// /// - public static unsafe bool TryGetUnicodeTextFromClipboard(out string outString) + public static unsafe bool TryGetClipboardUnicodeText(out string outString) { outString = string.Empty; if (!User32Methods.OpenClipboard(new IntPtr())) return true; From 1d3fdbec2ee7cff7c00a1d5cd38729f7a5b891a2 Mon Sep 17 00:00:00 2001 From: Afonin Dmitry Date: Mon, 30 Jul 2018 10:39:03 +0500 Subject: [PATCH 4/4] CloseClipboard return value is now handled #15 --- WinApi/User32/Helpers.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/WinApi/User32/Helpers.cs b/WinApi/User32/Helpers.cs index 9f218a9..e1f79c1 100644 --- a/WinApi/User32/Helpers.cs +++ b/WinApi/User32/Helpers.cs @@ -241,8 +241,6 @@ public static bool TrySetClipboardData(byte[] data, ClipboardFormat clipboardFor var result = User32Methods.SetClipboardData((uint)clipboardFormat, allocatedMemory); - User32Methods.CloseClipboard(); - //https://msdn.microsoft.com/en-us/library/windows/desktop/ms649051%28v=vs.85%29.aspx // If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. // The application may not write to or free the data once ownership has been transferred to the system, @@ -250,7 +248,7 @@ public static bool TrySetClipboardData(byte[] data, ClipboardFormat clipboardFor //The allocated memory should not be freed - return result != IntPtr.Zero; + return User32Methods.CloseClipboard() && result != IntPtr.Zero; } /// @@ -266,8 +264,6 @@ public static bool TrySetClipboardUnicodeText(string textToSet) var result = User32Methods.SetClipboardData((uint)ClipboardFormat.CF_UNICODETEXT, ptrToStr); - User32Methods.CloseClipboard(); - //https://msdn.microsoft.com/en-us/library/windows/desktop/ms649051%28v=vs.85%29.aspx // If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. // The application may not write to or free the data once ownership has been transferred to the system, @@ -275,7 +271,7 @@ public static bool TrySetClipboardUnicodeText(string textToSet) //The allocated memory should not be freed - return result != IntPtr.Zero; + return User32Methods.CloseClipboard() && result != IntPtr.Zero; } /// @@ -289,9 +285,8 @@ public static unsafe bool TryGetClipboardUnicodeText(out string outString) if (!User32Methods.OpenClipboard(new IntPtr())) return true; var ptrToData = User32Methods.GetClipboardData((uint)ClipboardFormat.CF_UNICODETEXT); - User32Methods.CloseClipboard(); - if (ptrToData == IntPtr.Zero) + if (User32Methods.CloseClipboard() == false || ptrToData == IntPtr.Zero) return false; outString = new string((char*)ptrToData);