Maison > développement back-end > Golang > Comment puis-je obtenir l'ID de processus ou le nom d'une application qui met à jour le presse-papiers ?

Comment puis-je obtenir l'ID de processus ou le nom d'une application qui met à jour le presse-papiers ?

王林
Libérer: 2024-02-12 13:40:06
avant
1036 Les gens l'ont consulté

Comment puis-je obtenir lID de processus ou le nom dune application qui met à jour le presse-papiers ?

Contenu de la question

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;
    }
}
Copier après la connexion

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();
Copier après la connexion

Solution de contournement

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.

La fonction

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);
}
Copier après la connexion
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;
            }
        }
    }
}
Copier après la connexion

Objet eventargspersonnalisé 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; }
}
Copier après la connexion

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;
}
Copier après la connexion

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!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal