134 lines
4.0 KiB
C#
134 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace FancyInput.Common
|
|
{
|
|
public class Utility
|
|
{
|
|
public static bool TrySetClipboardText(string text, out string errorDetail)
|
|
{
|
|
if (TrySetClipboardTextViaWin32(text, out var win32Error))
|
|
{
|
|
errorDetail = string.Empty;
|
|
return true;
|
|
}
|
|
|
|
errorDetail = win32Error == 0 ? "Win32 未知错误" : $"Win32 0x{win32Error:X8}";
|
|
return false;
|
|
}
|
|
|
|
private static bool TrySetClipboardTextViaWin32(string text, out int win32Error)
|
|
{
|
|
const int maxOpenRetries = 12;
|
|
const int openRetryDelayMs = 10;
|
|
const uint cfUnicodeText = 13;
|
|
const uint gmemMoveable = 0x0002;
|
|
const uint gmemZeroInit = 0x0040;
|
|
|
|
win32Error = 0;
|
|
var opened = false;
|
|
var hGlobal = IntPtr.Zero;
|
|
|
|
try
|
|
{
|
|
for (var i = 0; i < maxOpenRetries; i++)
|
|
{
|
|
if (OpenClipboard(IntPtr.Zero))
|
|
{
|
|
opened = true;
|
|
break;
|
|
}
|
|
|
|
win32Error = Marshal.GetLastWin32Error();
|
|
Thread.Sleep(openRetryDelayMs);
|
|
}
|
|
|
|
if (!opened)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!EmptyClipboard())
|
|
{
|
|
win32Error = Marshal.GetLastWin32Error();
|
|
return false;
|
|
}
|
|
|
|
var bytes = Encoding.Unicode.GetBytes(text + '\0');
|
|
hGlobal = GlobalAlloc(gmemMoveable | gmemZeroInit, (UIntPtr)bytes.Length);
|
|
if (hGlobal == IntPtr.Zero)
|
|
{
|
|
win32Error = Marshal.GetLastWin32Error();
|
|
return false;
|
|
}
|
|
|
|
var target = GlobalLock(hGlobal);
|
|
if (target == IntPtr.Zero)
|
|
{
|
|
win32Error = Marshal.GetLastWin32Error();
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
Marshal.Copy(bytes, 0, target, bytes.Length);
|
|
}
|
|
finally
|
|
{
|
|
GlobalUnlock(hGlobal);
|
|
}
|
|
|
|
if (SetClipboardData(cfUnicodeText, hGlobal) == IntPtr.Zero)
|
|
{
|
|
win32Error = Marshal.GetLastWin32Error();
|
|
return false;
|
|
}
|
|
|
|
// Ownership has transferred to the clipboard.
|
|
hGlobal = IntPtr.Zero;
|
|
return true;
|
|
}
|
|
finally
|
|
{
|
|
if (opened)
|
|
{
|
|
CloseClipboard();
|
|
}
|
|
|
|
if (hGlobal != IntPtr.Zero)
|
|
{
|
|
GlobalFree(hGlobal);
|
|
}
|
|
}
|
|
}
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern bool CloseClipboard();
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern bool EmptyClipboard();
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern IntPtr GlobalLock(IntPtr hMem);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern bool GlobalUnlock(IntPtr hMem);
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern IntPtr GlobalFree(IntPtr hMem);
|
|
}
|
|
}
|