C#使用WinApi监控和获取剪切板数据
[DllImport("user32.dll")]
public static extern int OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
public static extern int CloseClipboard();
[DllImport("user32.dll")]
public static extern uint EnumClipboardFormats(uint format);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetClipboardFormatNameW(int format, StringBuilder buffer, int maxLength);
[DllImport("user32.dll")]
public static extern bool IsClipboardFormatAvailable(int format);
[DllImport("user32.dll")]
public static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("Kernel32.dll")]
public static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("Kernel32.dll")]
public static extern bool GlobalUnlock(IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GlobalSize([In] IntPtr hMem);
[DllImport("user32.dll")]
public static extern uint GetClipboardSequenceNumber();
//输出内容:
//Current clipboard sequence number: 1037
//剪切板内容改变!
//fmt: 13 --- CF_UNICODETEXT
//fmt: 16 --- CF_LOCALE
//fmt: 1 --- CF_TEXT
//fmt: 7 --- CF_OEMTEXT
//获取剪切板内容 CF_UNICODETEXT: 这是测试数据
static void Main(string[] args)
{
uint sequenceNumber;
uint tmpSN = 0;
bool f = true;
while (true)
{
sequenceNumber = GetClipboardSequenceNumber();
if (f)
{
f = false;
}
else if (sequenceNumber == tmpSN)
{
continue;
}
tmpSN = sequenceNumber;
Console.WriteLine("Current clipboard sequence number: " + sequenceNumber);
OpenClipboard(IntPtr.Zero);
uint fmt = 0;
Console.WriteLine("剪切板内容改变!");
while ((fmt = EnumClipboardFormats(fmt)) != 0)
{
// 定义缓冲区和最大长度
StringBuilder buffer = new StringBuilder(256);
int maxLength = buffer.Capacity;
string fmtName = "";
switch (fmt)
{
case 2:
fmtName = "CF_BITMAP";
break;
case 8:
fmtName = "CF_DIB";
break;
case 17:
fmtName = "CF_DIBV5";
break;
case 5:
fmtName = "CF_DIF";
break;
case 0x0082:
fmtName = "CF_DSPBITMAP";
break;
case 0x008E:
fmtName = "CF_DSPENHMETAFILE";
break;
case 0x0083:
fmtName = "CF_DSPMETAFILEPICT";
break;
case 0x0081:
fmtName = "CF_DSPTEXT";
break;
case 14:
fmtName = "CF_ENHMETAFILE";
break;
case 0x0300:
fmtName = "CF_GDIOBJFIRST";
break;
case 0x03FF:
fmtName = "CF_GDIOBJLAST";
break;
case 15:
fmtName = "CF_HDROP";
break;
case 16:
fmtName = "CF_LOCALE";
break;
case 3:
fmtName = "CF_METAFILEPICT";
break;
case 7:
fmtName = "CF_OEMTEXT";
break;
case 0x0080:
fmtName = "CF_OWNERDISPLAY";
break;
case 9:
fmtName = "CF_PALETTE";
break;
case 10:
fmtName = "CF_PENDATA";
break;
case 0x0200:
fmtName = "CF_PRIVATEFIRST";
break;
case 0x02FF:
fmtName = "CF_PRIVATELAST";
break;
case 11:
fmtName = "CF_RIFF";
break;
case 4:
fmtName = "CF_SYLK";
break;
case 1:
fmtName = "CF_TEXT";
break;
case 6:
fmtName = "CF_TIFF";
break;
case 13:
fmtName = "CF_UNICODETEXT";
break;
case 12:
fmtName = "CF_WAVE";
break;
default:
//对于不是标准的剪切板格式
// 调用GetClipboardFormatNameW函数获取剪贴板格式名称
int result = GetClipboardFormatNameW((int)fmt, buffer, maxLength);
if (result > 0)
{
fmtName = buffer.ToString();
// 输出剪贴板格式名称
// Console.WriteLine("剪贴板格式 " + fmt + " 的名称是:" + buffer.ToString());
}
else
{
buffer.Clear();
buffer.Append("[Error]");
fmtName = buffer.ToString();
//Console.WriteLine("无法获取剪贴板格式 " + fmt + " 的名称");
}
break;
}
Console.WriteLine("fmt: " + fmt.ToString().PadRight(8) + "\t" + "---" + "\t" + fmtName);
}
if (IsClipboardFormatAvailable(13))//CF_UNICODETEXT
{
IntPtr hCpData = GetClipboardData(13);
IntPtr pGlobal = GlobalLock(hCpData);
byte[] bf = new byte[GlobalSize(pGlobal)];
if (pGlobal != IntPtr.Zero)
{
Marshal.Copy(pGlobal, bf, 0, bf.Length);
GlobalUnlock(pGlobal);
Console.WriteLine("获取剪切板内容 CF_UNICODETEXT: " + System.Text.Encoding.Unicode.GetString(bf));// bf.ToString() 不行,只会输出 System::char[]
}
else
{
Console.WriteLine("pGlobal 为 Null!");
}
}
CloseClipboard();
//窗口程序可用 AddClipboardFormatListener 来注册监听器,这样就不用使用死循环来检测剪切板数据是否变化了
//BOOL AddClipboardFormatListener(
// [in] HWND hwnd//要放置在剪贴板格式侦听器列表中的窗口的句柄。
//);
System.Threading.Thread.Sleep(1000);
Console.WriteLine();
}
}