日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C# 使用WinApi操作剪切板Clipboard

發(fā)布時間:2023/11/29 C# 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# 使用WinApi操作剪切板Clipboard 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言:

最近正好寫一個程序,需要操作剪切板

功能很簡單,只需要從剪切板內(nèi)讀取字符串,然后清空剪切板,然后再把字符串導入剪切板

我想當然的使用我最拿手的C#來完成這項工作,原因無他,因為.Net框架封裝了能實現(xiàn)這種功能的方法

然后就有了如下代碼

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

這段代碼,也是網(wǎng)頁上廣泛流傳的,使用.Net框架操作系統(tǒng)剪切板的方法,當然這個方法在某些情況下很管用

不過在我這確發(fā)生了點問題,主要的問題有兩點

首先,我對剪切板的操作需求有實時性,也就是,操作人員復制的一瞬間就應該截取到剪切板的數(shù)據(jù),處理完后再放入剪切板

結(jié)果

Clipboard.SetDataObject(Tex, false);

沒想到上面這條設(shè)置剪切板的指令竟然會卡焦點窗口的線程,比如說,我在A軟件執(zhí)行了一次復制操作,如果使用了上述代碼,那么A軟件強制線程堵塞大概幾百毫秒的樣子,反正很影響體驗,我推測是因為該命令會鎖定內(nèi)存導致的

那怎么辦,本著死馬當活馬醫(yī)的態(tài)度,我專門為該指令啟用了一個線程

Task.Factory.StartNew(()=> {Clipboard.Clear();Clipboard.SetDataObject(Text, false);});

使用了線程以后,因為操作滯后(線程啟動會延遲一會兒,并不實時)了,所以上述問題似乎解決了,但是沒想到出現(xiàn)了新的問題

string Tex = Clipboard.GetText().ToString();

上述從剪切板獲得字符串的指令,在默寫情況下,會卡滯住,然后程序在一分鐘之后,因為超時而被系統(tǒng)吊銷

emmmmm,在經(jīng)過幾番努力之后,我終于意識到,雖然.Net封裝了不少操作系統(tǒng)API的方法,使得一些IO操作變簡單不少,但是帶來的問題也是同樣大的,在遇到無法解決的問題的時候,會有點束手無策

于是不得已,我只能放棄使用過C#完成該項功能,想著幸好功能簡單,而且操作WinAPI其實最好的還是使用C++來寫,于是我用C++復現(xiàn)了上述功能

1 #include "stdafx.h" 2 #include <windows.h> 3 #include <iostream> 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);//分配內(nèi)存 10 char* Temp = (char*)THandle;//鎖定內(nèi)存,返回申請內(nèi)存的首地址 11 while (true) 12 { 13 HWND hWnd = NULL; 14 OpenClipboard(hWnd);//打開剪切板 15 if (IsClipboardFormatAvailable(CF_TEXT)) 16 { 17 HANDLE h = GetClipboardData(CF_TEXT);//獲取剪切板數(shù)據(jù) 18 char* p = (char*)GlobalLock(h); 19 GlobalUnlock(h); 20 if (strcmp(Temp, p)) 21 { 22 EmptyClipboard();//清空剪切板 23 HANDLE hHandle = GlobalAlloc(GMEM_FIXED, 1000);//分配內(nèi)存 24 char* pData = (char*)GlobalLock(hHandle);//鎖定內(nèi)存,返回申請內(nèi)存的首地址 25 strcpy(pData, p); 26 strcpy(Temp, p); 27 SetClipboardData(CF_TEXT, hHandle);//設(shè)置剪切板數(shù)據(jù) 28 GlobalUnlock(hHandle);//解除鎖定 29 } 30 } 31 CloseClipboard();//關(guān)閉剪切板 32 Sleep(500); 33 } 34 return 0; 35 } View Code

不愧是C++,使用上述代碼后,完美實現(xiàn)我需要的功能,而且不管是主程序,還是我寫的這個程序,都不會出現(xiàn)卡滯或者不工作的情況了,真是可喜可賀。

那么本教程就到此為止。

?

?

以下是正文

想著,既然我能用C++調(diào)用WinAPI完美實現(xiàn)我需要的功能,而且C#也能調(diào)用非托管的代碼來執(zhí)行WinAPI,那么我不是可以把上面C++寫的代碼移植到C#里面執(zhí)行?說干就干

首先,C#調(diào)用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);

操作剪切板需要調(diào)用的API大致就上面這些

有了API以后,我們還需要自己手動封裝方法

internal static void SetText(string text){if (!OpenClipboard(IntPtr.Zero))
        {
        SetText(text);
        return;
        }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;}

我們也就用到兩個方法,從剪切板獲得文本和設(shè)置文本到剪切板,哦關(guān)于SetClipboardData的第一個參數(shù)13是怎么來的問題,其實這個剪切板的格式參數(shù),下面有一張表,就是自從這里來的

public static class ClipboardFormat {/// <summary>/// 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./// </summary>public const int CF_TEXT = 1;/// <summary>/// A handle to a bitmap (<c>HBITMAP</c>)./// </summary>public const int CF_BITMAP = 2;/// <summary>/// Handle to a metafile picture format as defined by the <c>METAFILEPICT</c> structure. When passing a/// <c>CF_METAFILEPICT</c> handle by means of DDE, the application responsible for deleting <c>hMem</c> should/// also free the metafile referred to by the <c>CF_METAFILEPICT</c> handle./// </summary>public const int CF_METAFILEPICT = 3;/// <summary>/// Microsoft Symbolic Link (SYLK) format./// </summary>public const int CF_SYLK = 4;/// <summary>/// Software Arts' Data Interchange Format./// </summary>public const int CF_DIF = 5;/// <summary>/// Tagged-image file format./// </summary>public const int CF_TIFF = 6;/// <summary>/// 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./// </summary>public const int CF_OEMTEXT = 7;/// <summary>/// A memory object containing a <c>BITMAPINFO</c> structure followed by the bitmap bits./// </summary>public const int CF_DIB = 8;/// <summary>/// 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 <see cref="CF_PALETTE"/> (logical color palette) format, the application should use the/// <c>SelectPalette</c> and <c>RealizePalette</c> 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 <c>CF_PALETTE</c> format./// </summary>public const int CF_PALETTE = 9;/// <summary>/// Data for the pen extensions to the Microsoft Windows for Pen Computing./// </summary>public const int CF_PENDATA = 10;/// <summary>/// Represents audio data more complex than can be represented in a CF_WAVE standard wave format./// </summary>public const int CF_RIFF = 11;/// <summary>/// Represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz PCM./// </summary>public const int CF_WAVE = 12;/// <summary>/// Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character/// signals the end of the data./// </summary>public const int CF_UNICODETEXT = 13;/// <summary>/// A handle to an enhanced metafile (<c>HENHMETAFILE</c>)./// </summary>public const int CF_ENHMETAFILE = 14;/// <summary>/// A handle to type <c>HDROP</c> that identifies a list of files. An application can retrieve information/// about the files by passing the handle to the <c>DragQueryFile</c> function./// </summary>public const int CF_HDROP = 15;/// <summary>/// The data is a handle to the locale identifier associated with text in the clipboard. When you close the/// clipboard, if it contains <c>CF_TEXT</c> data but no <c>CF_LOCALE</c> data, the system automatically sets/// the <c>CF_LOCALE</c> format to the current input language. You can use the <c>CF_LOCALE</c> 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 <c>CF_LOCALE</c> to implicitly convert from/// <see cref="CF_TEXT"/> to <see cref="CF_UNICODETEXT"/>. Therefore, the correct code page table is used for/// the conversion./// </summary>public const int CF_LOCALE = 16;/// <summary>/// A memory object containing a <c>BITMAPV5HEADER</c> structure followed by the bitmap color space/// information and the bitmap bits./// </summary>public const int CF_DIBV5 = 17;/// <summary>/// Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive/// the <see cref="ClipboardMessages.WM_ASKCBFORMATNAME"/>, <see cref="ClipboardMessages.WM_HSCROLLCLIPBOARD"/>,/// <see cref="ClipboardMessages.WM_PAINTCLIPBOARD"/>, <see cref="ClipboardMessages.WM_SIZECLIPBOARD"/>, and/// <see cref="ClipboardMessages.WM_VSCROLLCLIPBOARD"/> messages. The <c>hMem</c> parameter must be <c>null</c>./// </summary>public const int CF_OWNERDISPLAY = 0x0080;/// <summary>/// Text display format associated with a private format. The <c>hMem</c> parameter must be a handle to data/// that can be displayed in text format in lieu of the privately formatted data./// </summary>public const int CF_DSPTEXT = 0x0081;/// <summary>/// Bitmap display format associated with a private format. The <c>hMem</c> parameter must be a handle to/// data that can be displayed in bitmap format in lieu of the privately formatted data./// </summary>public const int CF_DSPBITMAP = 0x0082;/// <summary>/// Metafile-picture display format associated with a private format. The <c>hMem</c> parameter must be a/// handle to data that can be displayed in metafile-picture format in lieu of the privately formatted data./// </summary>public const int CF_DSPMETAFILEPICT = 0x0083;/// <summary>/// Enhanced metafile display format associated with a private format. The <c>hMem</c> parameter must be a/// handle to data that can be displayed in enhanced metafile format in lieu of the privately formatted data./// </summary>public const int CF_DSPENHMETAFILE = 0x008E;/// <summary>/// Start of a range of integer values for application-defined GDI object clipboard formats. The end of the/// range is <see cref="CF_GDIOBJLAST"/>. Handles associated with clipboard formats in this range are not/// automatically deleted using the <c>GlobalFree</c> function when the clipboard is emptied. Also, when using/// values in this range, the <c>hMem</c> parameter is not a handle to a GDI object, but is a handle allocated/// by the <c>GlobalAlloc</c> function with the <c>GMEM_MOVEABLE</c> flag./// </summary>public const int CF_GDIOBJFIRST = 0x0300;/// <summary>/// See <see cref="CF_GDIOBJFIRST"/>./// </summary>public const int CF_GDIOBJLAST = 0x03FF;/// <summary>/// Start of a range of integer values for private clipboard formats. The range ends with/// <see cref="CF_PRIVATELAST"/>. Handles associated with private clipboard formats are not freed/// automatically; the clipboard owner must free such handles, typically in response to the/// <see cref="ClipboardMessages.WM_DESTROYCLIPBOARD"/> message./// </summary>public const int CF_PRIVATEFIRST = 0x0200;/// <summary>/// See <see cref="CF_PRIVATEFIRST"/>./// </summary>public const int CF_PRIVATELAST = 0x02FF; } View Code

在C++里面是不用指定數(shù)字的,只需要用CF_UNICODETEXT就行,不過.Net里面應該沒有對應的索引表,所以只能手動輸入(我這里是為了說明用才專門用數(shù)字,自己代碼那是索引的枚舉類)

上面兩個工作做完以后,就能實現(xiàn)功能了,功能代碼如下

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);}

是不是和最開始展示的調(diào)用.Net框架的方法一模一樣(笑),不過使用底層API實現(xiàn)的功能,就沒有那么多亂七八糟的Bug了,自己也很清楚到底實現(xiàn)了啥功能,同時也收獲了不少新知識(主要是非托管代碼調(diào)用的時候的注意事項什么的,還有,向非托管代碼傳遞數(shù)據(jù)的時候,最好多用Marshal類里面的方法,不然可能會出錯,畢竟這個類就是專門為非托管代碼而設(shè)立的)

接下來是新的發(fā)現(xiàn)

在研究MSDN上面關(guān)于剪切板的API的時候,發(fā)現(xiàn)了一個函數(shù)

bool AddClipboardFormatListener(HWND hwnd);

根據(jù)描述來講,是添加一個剪切板的監(jiān)控,在剪切板有任何變動的時候,通知你所指定的句柄的窗口,我一想,這不就是我所需要的么,有了這么一個API以后,其實我上面所展示的,使用死循環(huán)輪詢剪切板的方法就變得很傻逼,而且也很容易出錯了,于是,基于這個新發(fā)現(xiàn)的API,我重新更改了全部的程序邏輯,反而比原先的實現(xiàn)更加簡單了。

首先我們需要一個新的窗口或者控件來接收Windows消息更新后所發(fā)來的消息,只要New 一個form就行

public Form2(){InitializeComponent();AddClipboardFormatListener(this.Handle);}

然后我們在初始化組件的命令后面,把使用添加剪切板監(jiān)聽的API把當前窗口的句柄發(fā)給系統(tǒng),這樣系統(tǒng)在接收到剪切板改變的命令后,會把消息發(fā)給當前窗口

然后我們需要復寫WndProc方法

protected override void WndProc(ref Message m){if (m.Msg == 0x031D && Onice){var Temp = ClipboardControl.GetText(ClipboardFormat.CF_UNICODETEXT);if (!string.IsNullOrEmpty(Temp)){ClipboardControl.SetText(Temp);Onice = false;}}else if (!Onice){Onice = true;}else{base.WndProc(ref m);}}
? ?private bool Onice = true;

首先WndProc如果是Form類下面一個專門用來接收系統(tǒng)發(fā)送過來的消息的方法

然后關(guān)于m.Msg == 0x031D的0x031D在WinAPI定義上的意義是WM_CLIPBOARDUPDATE ,也就是剪切板更新事件,這個通過查找MSDN能夠找到

下面沒有特別奇怪的函數(shù),就是有一點需要注意,我們這里設(shè)置了剪切板數(shù)據(jù),相當于進行了一次更新,所以會在這一瞬間再次產(chǎn)生剪切板更新事件,然后又會通知這個方法,然后就會形成死循環(huán),我在這里用了一個布爾判斷來通過布爾狀態(tài)決定是否截取剪切板,不只有有沒有更好的辦法來實現(xiàn)

以上

轉(zhuǎn)載于:https://www.cnblogs.com/ACDIV/p/9114472.html

總結(jié)

以上是生活随笔為你收集整理的C# 使用WinApi操作剪切板Clipboard的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产十区 | 国产亚洲不卡 | 欧美激情爱爱 | 亚洲第一页色 | 深夜福利院| aⅴ在线免费观看 | 国产精品国产三级国产专区51 | 亚洲50p | 日本日皮视频 | 日韩aⅴ视频 | 一本一道波多野结衣一区二区 | 中文字幕网站 | 真实偷拍激情啪啪对白 | 亚洲精品一区二区三区精华液 | 欧美黄色一级视频 | 91九色偷拍 | 日韩一级片视频 | 亚洲s码欧洲m码国产av | 一本一道av无码中文字幕 | 特黄a级片 | 成人在线高清视频 | 在线免费观看污视频 | 国产成人综合一区二区三区 | 饥渴少妇色诱水电工 | 日本少妇xxxx | 亚洲欧美电影 | 国产剧情一区二区 | 日韩欧美在线一区二区 | 国产福利一区二区 | 国产熟女高潮视频 | 91av免费观看 | 免费国产91| 久久久久久久免费 | 亚瑟av | 日韩久久不卡 | 久久国| 日韩一级大片 | 妺妺窝人体色WWW精品 | 91精品国产日韩91久久久久久 | 一区二区三区四区亚洲 | 欧美成人片在线观看 | www网站在线观看 | 亚欧精品在线观看 | 最新激情网| 老司机午夜精品 | 精品动漫一区二区三区在线观看 | 欧美日韩成人精品 | 少妇久久久久久 | jizz日本在线播放 | 哪里可以看免费毛片 | 国产日韩欧美在线观看 | 老师的肉丝玉足夹茎 | 日本一道在线 | 精品久久久久久久久久久久久久久久久 | 狠狠看| 黄色69视频| 日韩视频在线观看一区二区三区 | 青草视频在线免费观看 | 亚洲涩情 | 久久综合热 | 精品中文字幕在线 | 无码人妻久久一区二区三区 | а中文在线天堂 | 国产无遮挡a片又黄又爽 | 在线观看不卡的av | xxx在线播放 | 毛片网站在线免费观看 | 北条麻妃久久 | 国产精品久久久久久久久久久久久久久久久久 | 99国产精品欲 | 精品国产区 | 欧美韩日一区二区 | 99久久久无码国产精品性 | 91亚洲国产精品 | 欧美成人三级在线 | 性欧美精品中出 | 熟女人妻在线视频 | 中国性老太hd大全69 | 成人午夜一区二区 | 成人在线视频一区 | 久婷婷 | 亚洲国产精品一区二区久久hs | 国产精品久久久久久久久久久久久久久久 | 免费观看成年人视频 | 国产精品二区视频 | 色噜噜av| 欧美一级在线观看视频 | 精品国产乱码久久久久久88av | 麻豆精品国产传媒 | 韩国三级hd中文字幕有哪些 | 网站免费黄色 | 成人福利网 | 日韩av电影手机在线观看 | 亚洲最大看欧美片网站 | 黄色一级图片 | av黄色免费在线观看 | 日韩欧美在线一区 | 欧美日韩一区二区三区视频 | 女生和男生一起插插插 |