Saya sedang mencipta pengurus papan keratan dalam c# dan kadangkala saya menghadapi situasi di mana papan keratan ditetapkan kepada kosong oleh sesetengah aplikasi.
Ini berlaku apabila contohnya excel menyahpilih sesuatu yang baru disalin, jadi saya perlu menentukan sama ada papan keratan itu kosong, tetapi bagaimanakah saya hendak mendapatkan nama aplikasi yang mengemas kini papan keratan?
Saya harap saya boleh mendapatkan hwnd
pemegang kepada aplikasi yang mengemas kini papan keratan supaya saya dapat mencari proses di belakangnya menggunakan kod berikut:
[dllimport("user32.dll", setlasterror = true)] public static extern uint getwindowthreadprocessid(intptr hwnd, out uint lpdwprocessid); ... protected override void wndproc(ref message m) { switch (m.msg) { case wm_clipboardupdate: // how to get the "handle" hwnd? intptr handle = ??? <============= how to get this one ??? // get the process id from the hwnd uint processid = 0; getwindowthreadprocessid(handle, out processid); // get the process name from the process id string processname = process.getprocessbyid((int)processid).processname; console.writeline("clipboard update event from [" + processname + "]"); break; } default: base.wndproc(ref m); break; } }
Saya harap saya boleh menggunakan message
对象中的 hwnd
dalam objek mesej
, tetapi ini nampaknya aplikasi saya sendiri - mungkin memberitahu aplikasi dengan id proses ini:
Sekiranya saya boleh mendapatkannya dengan cara lain maka itu juga tidak mengapa, tetapi saya akan menghargai sebarang pandangan tentang ini :-)
Penyelesaian
Berdasarkan jawapan @jimi, ianya mudah. Saya boleh menambah 3 baris berikut pada kod asal saya:
// Import the "GetClipboardOwner" function from the User32 library [DllImport("user32.dll")] public static extern IntPtr GetClipboardOwner(); ... // Replace the original line with "HOW TO GET THIS ONE" with this line below - this will give the HWnd handle for the application that has changed the clipboard: IntPtr handle = GetClipboardOwner();
Anda boleh menghubungi getclipboardowner()< /a> untuk mendapatkan pemegang tetingkap kali terakhir papan keratan ditetapkan atau dikosongkan (operasi yang mencetuskan pemberitahuan).
[...] Secara umumnya, pemilik papan keratan ialah tetingkap yang terakhir meletakkan data ke dalam papan keratan.
Fungsi papan klip kosong memperuntukkan pemilikan papan keratan.
Dalam beberapa kes khas, satu proses menghantar pemegang kosong kepada openclipboard(): baca bahagian kenyataan fungsi ini dan fungsi emptyclipboard.
Aplikasi mesti membuka papan klip sebelum memanggil papan klip kosong Dengan menggunakan fungsi openclipboard. Jika permohonan menyatakan Pemegang tetingkap adalah batal apabila membuka papan klip, papan klip kosong berjaya Tetapi menetapkan pemilik papan keratan kepada batal. Ambil perhatian bahawa ini mengakibatkan setclipboarddata gagal.
▶ Di sini saya menggunakan kelas terbitan nativewindow< /a> untuk menyediakan pendengar papan keratan. Tetingkap yang mengendalikan mesej kemas kini papan keratan dibuat dengan memulakan objek createparams dan menghantar parameter ini kepada kaedah nativewindow.createhandle(createparams), yang digunakan untuk mencipta tetingkap invisible.
Kemudian tulis semula pemberitahuan wndproc
,接收 wm_clipboardupdate
nativewindow yang dimulakan.
addclipboardformatlistener digunakan untuk meletakkan tetingkap dalam rantai pendengar papan keratan sistem.
▶ clipboardupdatemonitor
类在收到剪贴板通知时生成一个事件。事件中传递的自定义 clipboardchangedeventargs
对象包含由 getclipboardowner()
Pemegang kepada pemilik papan keratan, dikembalikan oleh getwindowthreadprocessid(), dan nama proses, dikembalikan oleh process.getprocessbyid().
Anda boleh menetapkan objek clipboardupdatemonitor
seperti ini:
Kelas ini juga boleh dimulakan dalam program.cs
private clipboardupdatemonitor clipboardmonitor = null; // [...] clipboardmonitor = new clipboardupdatemonitor(); clipboardmonitor.clipboardchangednotify += this.clipboardchanged; // [...] private void clipboardchanged(object sender, clipboardchangedeventargs e) { console.writeline(e.processid); console.writeline(e.processname); console.writeline(e.threadid); }
using system.diagnostics; using system.runtime.interopservices; using system.security.permissions; using system.windows.forms; public sealed class clipboardupdatemonitor : idisposable { private bool isdisposed = false; private static clipboardwindow window = null; public event eventhandler<clipboardchangedeventargs> clipboardchangednotify; public clipboardupdatemonitor() { window = new clipboardwindow(); if (!nativemethods.addclipboardformatlistener(window.handle)) { throw new typeinitializationexception(nameof(clipboardwindow), new exception("clipboardformatlistener could not be initialized")); } window.clipboardchanged += clipboardchangedevent; } private void clipboardchangedevent(object sender, clipboardchangedeventargs e) => clipboardchangednotify?.invoke(this, e); public void dispose() { if (!isdisposed) { // cannot allow to throw exceptions here: add more checks to verify that // the nativewindow still exists and its handle is a valid handle nativemethods.removeclipboardformatlistener(window.handle); window?.destroyhandle(); isdisposed = true; } } ~clipboardupdatemonitor() => dispose(); private class clipboardwindow : nativewindow { public event eventhandler<clipboardchangedeventargs> clipboardchanged; public clipboardwindow() { new securitypermission(securitypermissionflag.unmanagedcode).demand(); var cp = new createparams(); cp.caption = "clipboardwindow"; cp.height = 100; cp.width = 100; cp.parent = intptr.zero; cp.style = nativemethods.ws_clipchildren; cp.exstyle = nativemethods.ws_ex_controlparent | nativemethods.ws_ex_toolwindow; this.createhandle(cp); } protected override void wndproc(ref message m) { switch (m.msg) { case nativemethods.wm_clipboardupdate: intptr owner = nativemethods.getclipboardowner(); var threadid = nativemethods.getwindowthreadprocessid(owner, out uint processid); string processname = string.empty; if (processid != 0) { using (var proc = process.getprocessbyid((int)processid)) { processname = proc?.processname; } } clipboardchanged?.invoke(null, new clipboardchangedeventargs(processid, processname, threadid)); m.result = intptr.zero; break; default: base.wndproc(ref m); break; } } } }
Tersuai eventargs
objek yang membawa maklumat terkumpul tentang pemilik papan keratan:
public class clipboardchangedeventargs : eventargs { public clipboardchangedeventargs(uint processid, string processname, uint threadid) { this.processid = processid; this.processname = processname; this.threadid = threadid; } public uint processid { get; } public string processname { get; } public uint threadid { get; } }
nativemethods
Kategori:
internal static class NativeMethods { [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool AddClipboardFormatListener(IntPtr hwnd); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd); [DllImport("user32.dll")] internal static extern IntPtr GetClipboardOwner(); [DllImport("user32.dll", SetLastError = true)] internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); internal const int WM_CLIPBOARDUPDATE = 0x031D; internal const int WS_CLIPCHILDREN = 0x02000000; internal const int WS_EX_TOOLWINDOW = 0x00000080; internal const int WS_EX_CONTROLPARENT = 0x00010000; }
Atas ialah kandungan terperinci Bagaimanakah saya boleh mendapatkan ID proses atau nama aplikasi yang mengemas kini papan keratan?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!