首頁 > 後端開發 > Golang > 主體

如何取得更新剪貼簿的應用程式的進程ID或名稱?

王林
發布: 2024-02-12 13:40:06
轉載
890 人瀏覽過

如何取得更新剪貼簿的應用程式的進程ID或名稱?

問題內容

我正在用 c# 建立剪貼簿管理器,有時我會遇到剪貼簿被某些應用程式設定為空的情況。

這發生在例如excel 取消選擇剛剛複製的內容時,因此我需要確定剪貼簿是否為空,但是如何取得更新剪貼簿的應用程式名稱

我希望我能以某種方式獲得更新剪貼簿的應用程式的 hwnd 句柄,以便我可以使用以下程式碼查找其背後的進程:

[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;
    }
}
登入後複製

我希望我可以使用 message 物件中的 hwnd ,但這似乎是我自己的應用程式 - 可能是用此進程 id 通知應用程式:

如果我可以透過其他方式獲得它,那麼這當然也完全沒問題,但我將不勝感激對此的任何見解:-)

解決方案

根據@jimi的回答,這很簡單。我可以將以下 3 行新增到我的原始程式碼:

// 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();
登入後複製

解決方法

您可以呼叫getclipboardowner()< /a> 取得上次設定或清除剪貼簿(觸發通知的動作)的視窗句柄。

[...] 一般來說,剪貼簿擁有者是最後將資料放入剪貼簿的視窗。
emptyclipboard 函數指派剪貼簿所有權。

在某些特殊情況下,程序會將空句柄傳遞給 openclipboard():閱讀此函數的備註部分和 emptyclipboard 函數。

在呼叫 emptyclipboard 之前,應用程式必須開啟剪貼簿 透過使用 openclipboard 函數。如果應用程式指定 開啟剪貼簿時視窗句柄為null,emptyclipboard成功 但將剪貼簿擁有者設為 null。請注意,這會導致 setclipboarddata 失敗。

▶ 這裡我使用的是 nativewindow< /a> 衍生類別來設定剪貼簿偵聽器。處理剪貼簿更新訊息的視窗是透過初始化 建立的createparams 物件並將此參數傳遞給nativewindow.createhandle(createparams) 方法,用於建立一個不可見視窗。
然後重寫初始化的nativewindow的wndproc,接收 wm_clipboardupdate 通知。

addclipboardformatlistener 函數用於將視窗放置在系統剪貼簿偵聽器鏈中。

clipboardupdatemonitor 類別在收到剪貼簿通知時產生一個事件。事件中傳遞的自訂clipboardchangedeventargs 物件包含由getclipboardowner() 傳回的剪貼簿擁有者的句柄、由getwindowthreadprocessid() 和流程名稱,由process.getprocessbyid()

您可以像這樣設定 clipboardupdatemonitor 物件:
該類別也可以在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;
            }
        }
    }
}
登入後複製

自訂 eventargs 對象,用於攜帶收集的有關剪貼簿所有者的資訊:

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 類別:

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;
}
登入後複製

以上是如何取得更新剪貼簿的應用程式的進程ID或名稱?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!