Heim  >  Artikel  >  Backend-Entwicklung  >  Wie erhalte ich die Prozess-ID oder den Namen einer Anwendung, die die Zwischenablage aktualisiert?

Wie erhalte ich die Prozess-ID oder den Namen einer Anwendung, die die Zwischenablage aktualisiert?

王林
王林nach vorne
2024-02-12 13:40:06893Durchsuche

Wie erhalte ich die Prozess-ID oder den Namen einer Anwendung, die die Zwischenablage aktualisiert?

Frageninhalt

Ich erstelle einen Zwischenablage-Manager in C# und manchmal stoße ich auf eine Situation, in der die Zwischenablage von einigen Anwendungen auf leer gesetzt wird.

Das passiert, wenn beispielsweise Excel etwas abwählt, das gerade kopiert wurde, also muss ich feststellen, ob die Zwischenablage leer ist, aber Wie erhalte ich den Namen der Anwendung, die die Zwischenablage aktualisiert hat?

Ich wünschte, ich könnte irgendwie ein hwnd-Handle für die Anwendung bekommen, die die Zwischenablage aktualisiert, damit ich den Prozess dahinter finden kann, indem ich den folgenden Code verwende:

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

Ich wünschte, ich könnte das message 对象中的 hwnd im message-Objekt verwenden, aber dies scheint meine eigene Anwendung zu sein – wahrscheinlich wird die Anwendung mit dieser Prozess-ID benachrichtigt:

Wenn ich es auf andere Weise hinbekomme, ist das natürlich auch völlig in Ordnung, aber ich würde mich über jeden Einblick hierzu freuen :-)

Lösung

Basierend auf der Antwort von @jimi ist es einfach. Ich kann meinem ursprünglichen Code die folgenden 3 Zeilen hinzufügen:

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

Workaround

Sie können getclipboardowner() aufrufen, um das Fensterhandle des letzten Mals abzurufen, als die Zwischenablage festgelegt oder gelöscht wurde (der Vorgang, der die Benachrichtigung ausgelöst hat).

[...] Im Allgemeinen ist der Besitzer der Zwischenablage das Fenster, das zuletzt Daten in die Zwischenablage eingefügt hat.
Die Funktion emptyclipboard weist den Besitz der Zwischenablage zu.

In einigen Sonderfällen übergibt ein Prozess ein leeres Handle an openclipboard(): Lesen Sie den Abschnitt „Bemerkungen“ dieser Funktion und der Funktion emptyclipboard.

Die Anwendung muss die Zwischenablage öffnen, bevor sie emptyclipboard aufruft Durch die Verwendung der openclipboard-Funktion. Wenn die Anwendung dies vorgibt Das Fensterhandle ist beim Öffnen der Zwischenablage null, leeres Clipboard ist erfolgreich Setzt aber den Besitzer der Zwischenablage auf null. Beachten Sie, dass dies dazu führt setclipboarddata ist fehlgeschlagen.

▶ Hier verwende ich die von nativewindow abgeleitete Klasse, um den Zwischenablage-Listener einzurichten. Das Fenster, das Nachrichten zur Aktualisierung der Zwischenablage verarbeitet, wird erstellt, indem das Objekt „createparams“ initialisiert und dieser Parameter an die Methode „nativewindow.createhandle(createparams)“ übergeben wird, mit der ein „unsichtbares“ Fenster erstellt wird. Schreiben Sie dann die -Benachrichtigung des initialisierten nativen Fensters neu. Die Funktion addclipboardformatlistener
wird verwendet, um ein Fenster in der System-Zwischenablage-Listener-Kette zu platzieren. wndproc,接收 wm_clipboardupdate

Das Handle für den Besitzer der Zwischenablage, zurückgegeben von

getwindowthreadprocessid(), und der Prozessname, zurückgegeben von process.getprocessbyid()

.

clipboardupdatemonitor 类在收到剪贴板通知时生成一个事件。事件中传递的自定义 clipboardchangedeventargs 对象包含由 getclipboardowner()Sie können das -Objekt wie folgt festlegen: Diese Klasse kann auch in

initialisiert werden

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;
            }
        }
    }
}
clipboardupdatemonitorBenutzerdefiniertes
Objekt, das gesammelte Informationen über den Besitzer der Zwischenablage enthält:
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; }
}
program.cs
Kategorie:

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

Das obige ist der detaillierte Inhalt vonWie erhalte ich die Prozess-ID oder den Namen einer Anwendung, die die Zwischenablage aktualisiert?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen