标签:ict lob correct repr compare spl receive ios current
前言:
最近正好写一个程序,需要操作剪切板
功能很简单,只需要从剪切板内读取字符串,然后清空剪切板,然后再把字符串导入剪切板
我想当然的使用我最拿手的C#来完成这项工作,原因无他,因为.Net框架封装了能实现这种功能的方法
然后就有了如下代码
1 string Temp = "";
2 while (true)
3 {
4 string Tex = Clipboard.GetText().ToString();
5 if (!string.IsNullOrWhiteSpace(Tex) && Temp != Tex)
6 {
7 Clipboard.Clear();
8 Clipboard.SetDataObject(Tex, false);
9 Temp = Tex;
10 }
11 Thread.Sleep(1);
12 }
View Code
这段代码,也是网页上广泛流传的,使用.Net框架操作系统剪切板的方法,当然这个方法在某些情况下很管用
不过在我这确发生了点问题,主要的问题有两点
首先,我对剪切板的操作需求有实时性,也就是,操作人员复制的一瞬间就应该截取到剪切板的数据,处理完后再放入剪切板
结果
Clipboard.SetDataObject(Tex, false);
没想到上面这条设置剪切板的指令竟然会卡焦点窗口的线程,比如说,我在A软件执行了一次复制操作,如果使用了上述代码,那么A软件强制线程堵塞大概几百毫秒的样子,反正很影响体验,我推测是因为该命令会锁定内存导致的
那怎么办,本着死马当活马医的态度,我专门为该指令启用了一个线程
Task.Factory.StartNew(()=>
{
Clipboard.Clear();
Clipboard.SetDataObject(Text, false);
});
使用了线程以后,因为操作滞后(线程启动会延迟一会儿,并不实时)了,所以上述问题似乎解决了,但是没想到出现了新的问题
string Tex = Clipboard.GetText().ToString();
上述从剪切板获得字符串的指令,在默写情况下,会卡滞住,然后程序在一分钟之后,因为超时而被系统吊销
emmmmm,在经过几番努力之后,我终于意识到,虽然.Net封装了不少操作系统API的方法,使得一些IO操作变简单不少,但是带来的问题也是同样大的,在遇到无法解决的问题的时候,会有点束手无策
于是不得已,我只能放弃使用过C#完成该项功能,想着幸好功能简单,而且操作WinAPI其实最好的还是使用C++来写,于是我用C++复现了上述功能
1 #include "stdafx.h"
2 #include 3 #include 4 using namespace std;
5 #pragma comment(linker,"/subsystem:windows /entry:mainCRTStartup")
6
7 int main(int argc, _TCHAR* argv[])
8 {
9 HANDLE THandle = GlobalAlloc(GMEM_FIXED, 1000);//分配内存
10 char* Temp = (char*)THandle;//锁定内存,返回申请内存的首地址
11 while (true)
12 {
13 HWND hWnd = NULL;
14 OpenClipboard(hWnd);//打开剪切板
15 if (IsClipboardFormatAvailable(CF_TEXT))
16 {
17 HANDLE h = GetClipboardData(CF_TEXT);//获取剪切板数据
18 char* p = (char*)GlobalLock(h);
19 GlobalUnlock(h);
20 if (strcmp(Temp, p))
21 {
22 EmptyClipboard();//清空剪切板
23 HANDLE hHandle = GlobalAlloc(GMEM_FIXED, 1000);//分配内存
24 char* pData = (char*)GlobalLock(hHandle);//锁定内存,返回申请内存的首地址
25 strcpy(pData, p);
26 strcpy(Temp, p);
27 SetClipboardData(CF_TEXT, hHandle);//设置剪切板数据
28 GlobalUnlock(hHandle);//解除锁定
29 }
30 }
31 CloseClipboard();//关闭剪切板
32 Sleep(500);
33 }
34 return 0;
35 }
View Code
不愧是C++,使用上述代码后,完美实现我需要的功能,而且不管是主程序,还是我写的这个程序,都不会出现卡滞或者不工作的情况了,真是可喜可贺。
那么本教程就到此为止。
以下是正文
想着,既然我能用C++调用WinAPI完美实现我需要的功能,而且C#也能调用非托管的代码来执行WinAPI,那么我不是可以把上面C++写的代码移植到C#里面执行?说干就干
首先,C#调用WinAPI需要先申明
[DllImport("User32")]
internal static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("User32")]
internal static extern bool CloseClipboard();
[DllImport("User32")]
internal static extern bool EmptyClipboard();
[DllImport("User32")]
internal static extern bool IsClipboardFormatAvailable(int format);
[DllImport("User32")]
internal static extern IntPtr GetClipboardData(int uFormat);
[DllImport("User32", CharSet = CharSet.Unicode)]
internal static extern IntPtr SetClipboardData(int uFormat, IntPtr hMem);
操作剪切板需要调用的API大致就上面这些
有了API以后,我们还需要自己手动封装方法
internal static void SetText(string text)
{
OpenClipboard(IntPtr.Zero);
EmptyClipboard();
SetClipboardData(13, Marshal.StringToHGlobalUni(text));
CloseClipboard();
}
internal static string GetText(int format)
{
string value = string.Empty;
OpenClipboard(IntPtr.Zero);
if (IsClipboardFormatAvailable(format))
{
IntPtr ptr = NativeMethods.GetClipboardData(format);
if (ptr != IntPtr.Zero)
{
value = Marshal.PtrToStringUni(ptr);
}
}
CloseClipboard();
return value;
}
我们也就用到两个方法,从剪切板获得文本和设置文本到剪切板,哦关于SetClipboardData的第一个参数13是怎么来的问题,其实这个剪切板的格式参数,下面有一张表,就是自从这里来的
public static class ClipboardFormat
{
///
/// Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals
/// the end of the data. Use this format for ANSI text.
///
public const int CF_TEXT = 1;
///
/// A handle to a bitmap (HBITMAP).
///
public const int CF_BITMAP = 2;
///
/// Handle to a metafile picture format as defined by the METAFILEPICT structure. When passing a
/// CF_METAFILEPICT handle by means of DDE, the application responsible for deleting hMem should
/// also free the metafile referred to by the CF_METAFILEPICT handle.
///
public const int CF_METAFILEPICT = 3;
///
/// Microsoft Symbolic Link (SYLK) format.
///
public const int CF_SYLK = 4;
///
/// Software Arts‘ Data Interchange Format.
///
public const int CF_DIF = 5;
///
/// Tagged-image file format.
///
public const int CF_TIFF = 6;
///
/// Text format containing characters in the OEM character set. Each line ends with a carriage return/linefeed
/// (CR-LF) combination. A null character signals the end of the data.
///
public const int CF_OEMTEXT = 7;
///
/// A memory object containing a BITMAPINFO structure followed by the bitmap bits.
///
public const int CF_DIB = 8;
///
/// Handle to a color palette. Whenever an application places data in the clipboard that depends on or assumes
/// a color palette, it should place the palette on the clipboard as well. If the clipboard contains data in
/// the (logical color palette) format, the application should use the
/// SelectPalette and RealizePalette functions to realize (compare) any other data in the
/// clipboard against that logical palette. When displaying clipboard data, the clipboard always uses as its
/// current palette any object on the clipboard that is in the CF_PALETTE format.
///
public const int CF_PALETTE = 9;
///
/// Data for the pen extensions to the Microsoft Windows for Pen Computing.
///
public const int CF_PENDATA = 10;
///
/// Represents audio data more complex than can be represented in a CF_WAVE standard wave format.
///
public const int CF_RIFF = 11;
///
/// Represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz PCM.
///
public const int CF_WAVE = 12;
///
/// Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character
/// signals the end of the data.
///
public const int CF_UNICODETEXT = 13;
///
/// A handle to an enhanced metafile (HENHMETAFILE).
///
public const int CF_ENHMETAFILE = 14;
///
/// A handle to type HDROP that identifies a list of files. An application can retrieve information
/// about the files by passing the handle to the DragQueryFile function.
///
public const int CF_HDROP = 15;
///
/// The data is a handle to the locale identifier associated with text in the clipboard. When you close the
/// clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets
/// the CF_LOCALE format to the current input language. You can use the CF_LOCALE format to
/// associate a different locale with the clipboard text.
/// An application that pastes text from the clipboard can retrieve this format to determine which character
/// set was used to generate the text.
/// Note that the clipboard does not support plain text in multiple character sets. To achieve this, use a
/// formatted text data type such as RTF instead.
/// The system uses the code page associated with CF_LOCALE to implicitly convert from
/// to . Therefore, the correct code page table is used for
/// the conversion.
///
public const int CF_LOCALE = 16;
///
/// A memory object containing a BITMAPV5HEADER structure followed by the bitmap color space
/// information and the bitmap bits.
///
public const int CF_DIBV5 = 17;
///
/// Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive
/// the , ,
/// , , and
/// messages. The hMem parameter must be null.
///
public const int CF_OWNERDISPLAY = 0x0080;
///
/// Text display format associated with a private format. The hMem parameter must be a handle to data
/// that can be displayed in text format in lieu of the privately formatted data.
///
public const int CF_DSPTEXT = 0x0081;
///
/// Bitmap display format associated with a private format. The hMem parameter must be a handle to
/// data that can be displayed in bitmap format in lieu of the privately formatted data.
///
public const int CF_DSPBITMAP = 0x0082;
///
/// Metafile-picture display format associated with a private format. The hMem parameter must be a
/// handle to data that can be displayed in metafile-picture format in lieu of the privately formatted data.
///
public const int CF_DSPMETAFILEPICT = 0x0083;
///
/// Enhanced metafile display format associated with a private format. The hMem parameter must be a
/// handle to data that can be displayed in enhanced metafile format in lieu of the privately formatted data.
///
public const int CF_DSPENHMETAFILE = 0x008E;
///
/// Start of a range of integer values for application-defined GDI object clipboard formats. The end of the
/// range is . Handles associated with clipboard formats in this range are not
/// automatically deleted using the GlobalFree function when the clipboard is emptied. Also, when using
/// values in this range, the hMem parameter is not a handle to a GDI object, but is a handle allocated
/// by the GlobalAlloc function with the GMEM_MOVEABLE flag.
///
public const int CF_GDIOBJFIRST = 0x0300;
///
/// See .
///
public const int CF_GDIOBJLAST = 0x03FF;
///
/// Start of a range of integer values for private clipboard formats. The range ends with
/// . Handles associated with private clipboard formats are not freed
/// automatically; the clipboard owner must free such handles, typically in response to the
/// message.
///
public const int CF_PRIVATEFIRST = 0x0200;
///
/// See .
///
public const int CF_PRIVATELAST = 0x02FF;
}
View Code
在C++里面是不用指定数字的,只需要用CF_UNICODETEXT就行,不过.Net里面应该没有对应的索引表,所以只能手动输入(我这里是为了说明用才专门用数字,自己代码那是索引的枚举类)
上面两个工作做完以后,就能实现功能了,功能代码如下
var LastS = string.Empty;
while (!CancelInfoClipboard.IsCancellationRequested)
{
var Temp = ClipboardControl.GetText(ClipboardFormat.CF_UNICODETEXT);
if (!string.IsNullOrEmpty(Temp) && Temp != LastS)
{
ClipboardControl.SetText(Temp);
LastS = Temp;
}
Thread.Sleep(50);
}
是不是和最开始展示的调用.Net框架的方法一模一样(笑),不过使用底层API实现的功能,就没有那么多乱七八糟的Bug了,自己也很清楚到底实现了啥功能,同时也收获了不少新知识(主要是非托管代码调用的时候的注意事项什么的,还有,向非托管代码传递数据的时候,最好多用Marshal类里面的方法,不然可能会出错,毕竟这个类就是专门为非托管代码而设立的)
以上
C# 使用WinApi操作剪切板Clipboard
标签:ict lob correct repr compare spl receive ios current
原文地址:https://www.cnblogs.com/ACDIV/p/9114472.html