Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Samples/Sample.SimpleWindow/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -16,6 +12,7 @@ static int Main(string[] args)
{
using (var win = Window.Create<AppWindow>("Hello"))
{
User32Methods.AddClipboardFormatListener(win.Handle);
win.Show();
return new EventLoop().Run(win);
}
Expand Down Expand Up @@ -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);
}
Expand Down
9 changes: 9 additions & 0 deletions Samples/Sample.Win32/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
Expand Down
20 changes: 20 additions & 0 deletions WinApi/User32/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5230,5 +5230,25 @@ public enum WM
USER = 0x0400
}

public enum ClipboardFormat : uint
{
/// <summary>
/// A handle to a bitmap (HBITMAP)
/// </summary>
CF_BITMAP = 2u,
/// <summary>
/// Flag for text-format
/// </summary>
CF_TEXT = 1u,
/// <summary>
/// Flag for unicode-text-format
/// </summary>
CF_UNICODETEXT = 13u,

/// <summary>
/// no format
/// </summary>
CF_ZERO = 0u
}
#endregion
}
65 changes: 65 additions & 0 deletions WinApi/User32/Helpers.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand Down Expand Up @@ -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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try-finally is useless here. Marshal.Copy is not going to throw. Infact AllocHGlobal is the one that can throw that's outside the scope - though it's not needed to handle it. Just simple statements will do, since if OutOfMemory is thrown, the application will have to react to it anyway.

{
Marshal.Copy(data, 0, allocatedMemory, bytesLength);

var result = User32Methods.SetClipboardData((uint)ClipboardFormat.CF_TEXT, allocatedMemory);

if (result == IntPtr.Zero)
Copy link
Owner

@prasannavl prasannavl May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing exceptions on a native API that indicates an error result is a no no. Instead, a better design would be to make it return a bool if IntPtr is zero, so the application can act in whichever way it deems necessary.

throw new Exception(Kernel32Methods.GetLastError().ToString());
}
finally
{
Marshal.FreeHGlobal(allocatedMemory);
}
}
User32Methods.CloseClipboard();

}

public static unsafe string GetUnicodeTextFromClipboard()
{
var outString = default(string);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default of string is null. I'd try to be explicit, so there are less chances of confusion of a consumer thinking it'll always return a string, and it's more readable. Just don't initialise it instead, and move it into the if statement. Just return a null in the end.

if (User32Methods.OpenClipboard(new IntPtr()))
{
var data = (char*)User32Methods.GetClipboardData((uint) ClipboardFormat.CF_UNICODETEXT);
outString = new string(data);
}
User32Methods.CloseClipboard();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has to be moved above into the if statement.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prasannavl, Oh, right, and in the TrySetClipboardData method as well. Damn, didn't see it at first. Will update it shortly, sorry to keep you waiting.

return outString;
}

public static unsafe string GetTextFromClipboard()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comments as the above method.

{
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;
}
}
}
}
58 changes: 58 additions & 0 deletions WinApi/User32/Methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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

/// <summary>
/// Opens the clipboard for examination and prevents other applications from modifying the clipboard content.
/// </summary>
/// <param name="hWndNewOwner">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.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
[DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern bool OpenClipboard(IntPtr hWndNewOwner);
/// <summary>
/// Closes the clipboard.
/// </summary>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
[DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern bool CloseClipboard();
/// <summary>
/// Retrieves data from the clipboard in a specified format. The clipboard must have been opened previously.
/// </summary>
/// <param name="uFormat">A clipboard format.</param>
/// <returns>If the function succeeds, the return value is the handle to a clipboard object in the specified format.</returns>
[DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr GetClipboardData(uint uFormat);

/// <summary>
/// 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
/// </summary>
/// <param name="uFormat">The clipboard format</param>
/// <param name="handle">A handle to the data in the specified format</param>
/// <returns>If the function succeeds, the return value is the handle to the data.</returns>
[DllImport(LibraryName, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr SetClipboardData(uint uFormat, IntPtr handle);

/// <summary>
/// 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.
/// </summary>
/// <returns></returns>
[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
}
}