Maison  >  Article  >  développement back-end  >  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 ?

王林
王林avant
2024-02-12 13:40:06893parcourir

Comment puis-je obtenir l’ID de processus ou le nom d’une 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;
    }
}

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

Solution de contournement

Vous pouvez appeler getclipboardowner() 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 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);
}
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 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; }
}

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer