124 lines
3.8 KiB
C#
124 lines
3.8 KiB
C#
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace Automata.Game;
|
|
|
|
/// <summary>
|
|
/// Win32 clipboard access without WinForms dependency.
|
|
/// </summary>
|
|
public static class ClipboardHelper
|
|
{
|
|
private const int MaxRetries = 5;
|
|
private const int RetryDelayMs = 30;
|
|
|
|
public static string Read()
|
|
{
|
|
for (var attempt = 0; attempt < MaxRetries; attempt++)
|
|
{
|
|
if (ClipboardNative.OpenClipboard(IntPtr.Zero))
|
|
{
|
|
try
|
|
{
|
|
var handle = ClipboardNative.GetClipboardData(ClipboardNative.CF_UNICODETEXT);
|
|
if (handle == IntPtr.Zero) return "";
|
|
|
|
var ptr = ClipboardNative.GlobalLock(handle);
|
|
if (ptr == IntPtr.Zero) return "";
|
|
|
|
try
|
|
{
|
|
return Marshal.PtrToStringUni(ptr) ?? "";
|
|
}
|
|
finally
|
|
{
|
|
ClipboardNative.GlobalUnlock(handle);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
ClipboardNative.CloseClipboard();
|
|
}
|
|
}
|
|
Thread.Sleep(RetryDelayMs);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
public static void Write(string text)
|
|
{
|
|
for (var attempt = 0; attempt < MaxRetries; attempt++)
|
|
{
|
|
if (ClipboardNative.OpenClipboard(IntPtr.Zero))
|
|
{
|
|
try
|
|
{
|
|
ClipboardNative.EmptyClipboard();
|
|
var bytes = Encoding.Unicode.GetBytes(text + "\0");
|
|
var hGlobal = ClipboardNative.GlobalAlloc(ClipboardNative.GMEM_MOVEABLE, (UIntPtr)bytes.Length);
|
|
if (hGlobal == IntPtr.Zero) return;
|
|
|
|
var ptr = ClipboardNative.GlobalLock(hGlobal);
|
|
if (ptr == IntPtr.Zero)
|
|
{
|
|
ClipboardNative.GlobalFree(hGlobal);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
Marshal.Copy(bytes, 0, ptr, bytes.Length);
|
|
}
|
|
finally
|
|
{
|
|
ClipboardNative.GlobalUnlock(hGlobal);
|
|
}
|
|
|
|
ClipboardNative.SetClipboardData(ClipboardNative.CF_UNICODETEXT, hGlobal);
|
|
return;
|
|
}
|
|
finally
|
|
{
|
|
ClipboardNative.CloseClipboard();
|
|
}
|
|
}
|
|
Thread.Sleep(RetryDelayMs);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static partial class ClipboardNative
|
|
{
|
|
public const uint CF_UNICODETEXT = 13;
|
|
public const uint GMEM_MOVEABLE = 0x0002;
|
|
|
|
[LibraryImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
public static partial bool OpenClipboard(IntPtr hWndNewOwner);
|
|
|
|
[LibraryImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
public static partial bool CloseClipboard();
|
|
|
|
[LibraryImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
public static partial bool EmptyClipboard();
|
|
|
|
[LibraryImport("user32.dll")]
|
|
public static partial IntPtr GetClipboardData(uint uFormat);
|
|
|
|
[LibraryImport("user32.dll")]
|
|
public static partial IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
|
|
|
|
[LibraryImport("kernel32.dll")]
|
|
public static partial IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
|
|
|
|
[LibraryImport("kernel32.dll")]
|
|
public static partial IntPtr GlobalLock(IntPtr hMem);
|
|
|
|
[LibraryImport("kernel32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
public static partial bool GlobalUnlock(IntPtr hMem);
|
|
|
|
[LibraryImport("kernel32.dll")]
|
|
public static partial IntPtr GlobalFree(IntPtr hMem);
|
|
}
|