Je crée un gestionnaire de presse-papiers en c# et parfois je rencontre une situation où le presse-papiers est défini pour se vider par certaines applications.
Cela se produit lorsque, par exemple, Excel désélectionne quelque chose qui vient d'être copié, je dois donc déterminer si le presse-papiers est vide, mais comment puis-je obtenir le nom de l'application qui a mis à jour le presse-papiers ?
J'aimerais pouvoir obtenir d'une manière ou d'une autre un hwnd
identifiant pour l'application qui met à jour le presse-papiers afin de pouvoir trouver le processus derrière cela en utilisant le code suivant :
[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; } }
J'aimerais pouvoir utiliser le message
对象中的 hwnd
dans l'objet message
, mais cela semble être ma propre application - notifiant probablement l'application avec cet identifiant de processus :
Si je peux l'obtenir d'une autre manière, c'est aussi tout à fait bien, bien sûr, mais j'apprécierais tout aperçu à ce sujet :-)
Solution
D'après la réponse de @jimi, c'est facile. Je peux ajouter les 3 lignes suivantes à mon code d'origine :
// 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();
Vous pouvez appeler getclipboardowner()< /a> pour obtenir le handle de fenêtre de la dernière fois que le presse-papiers a été défini ou effacé (l'opération qui a déclenché la notification).
[...] De manière générale, le propriétaire du presse-papiers est la fenêtre qui a mis les données en dernier dans le presse-papiers.
La fonction emptyclipboard attribue la propriété du presse-papiers.
Dans certains cas particuliers, un processus passe un handle vide à openclipboard() : lisez la section remarques de cette fonction et la fonction emptyclipboard.
L'application doit ouvrir le presse-papiers avant d'appeler emptyclipboard En utilisant la fonction openclipboard. Si la demande précise Le handle de fenêtre est nul lors de l'ouverture du presse-papiers, le presse-papier vide réussit Mais définit le propriétaire du presse-papiers sur null. Notez que cela entraîne setclipboarddata a échoué.
▶ Ici, j'utilise la classe dérivée nativewindow< /a> pour configurer l'écouteur du presse-papiers. La fenêtre qui gère les messages de mise à jour du presse-papiers est créée en initialisant l'objet createparams et en passant ce paramètre à la méthode nativewindow.createhandle(createparams), qui est utilisée pour créer une fenêtre invisible.
Réécrivez ensuite la notification wndproc
,接收 wm_clipboardupdate
de la fenêtre native initialisée.
addclipboardformatlistener est utilisée pour placer une fenêtre dans la chaîne d'écoute du presse-papiers du système.
▶ clipboardupdatemonitor
类在收到剪贴板通知时生成一个事件。事件中传递的自定义 clipboardchangedeventargs
对象包含由 getclipboardowner()
Le handle du propriétaire du presse-papiers, renvoyé par getwindowthreadprocessid(), et le nom du processus, renvoyé par process.getprocessbyid().
Vous pouvez définir l'objet clipboardupdatemonitor
comme ceci :
Cette classe peut également être initialisée en 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; } } } }
Objet eventargs
personnalisé contenant des informations collectées sur le propriétaire du presse-papiers :
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
Catégorie :
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; }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!