简体   繁体   English

如何在rust中制作剪贴板板监视器

[英]How to make a clipboard board monitor in rust

I am trying to make a clipboard manager for windows in rust and am using winapi-rs crate to use winapi.我正在尝试为 rust 中的 windows 创建剪贴板管理器,并使用winapi-rs crate 来使用 winapi。

My current implementation is as follows:我目前的实现如下:

src/clipboard.rs:

use std::mem::zeroed;
use std::ptr;

use winapi::shared::windef::HWND;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::winuser::{
    AddClipboardFormatListener,
    RemoveClipboardFormatListener,
    CreateWindowExW,
    RegisterClassW,
    WNDCLASSW,
    WM_CREATE,
    WM_DESTROY,
    WM_CLIPBOARDUPDATE,
    HWND_MESSAGE,
    DefWindowProcW
};
use winapi::shared::minwindef::{LRESULT, UINT, WPARAM, LPARAM, BOOL};

static mut ADDED_LISTENER: BOOL = 0;

unsafe extern "system" fn callback_proc(h_wnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
    println!("called");
    (match msg {
        WM_CREATE => {
            ADDED_LISTENER = AddClipboardFormatListener(h_wnd);
            if ADDED_LISTENER == 1 { 0 } else { -1 }
        }
        WM_DESTROY => {
            if ADDED_LISTENER == 1 {
                RemoveClipboardFormatListener(h_wnd);
                ADDED_LISTENER = 0;
            }
            0
        }
        WM_CLIPBOARDUPDATE => {
            println!("clipboard updated.");
            0
        },
        _ => DefWindowProcW(h_wnd, msg, wparam, lparam)
    }) as LRESULT
}

pub fn run() {
    unsafe {
        let hinst = GetModuleHandleW(ptr::null_mut());
        let wnd_class = WNDCLASSW {
            hInstance: hinst,
            lpfnWndProc: Some(callback_proc),
            lpszClassName: &[67 as u16, 108 as u16, 105 as u16, 112 as u16, 98 as u16, 111 as u16, 97 as u16, 114 as u16, 100 as u16, 77 as u16, 101 as u16, 115 as u16, 115 as u16, 97 as u16, 103 as u16, 101 as u16, 87 as u16, 105 as u16, 110 as u16, 100 as u16, 111 as u16, 119 as u16] as *const u16,
            ..zeroed::<WNDCLASSW>()
        };

        let class_atom = RegisterClassW(&wnd_class as *const WNDCLASSW);

        CreateWindowExW(class_atom.into(), wnd_class.lpszClassName, ptr::null(), 0, 0, 0, 0, 0, HWND_MESSAGE, ptr::null_mut(), hinst, ptr::null_mut());
    }

    loop { } // Added this as the code was exiting immediately
}

src/main.rs:

mod clipboard;

fn main() {
    clipboard::run();
}

I got help from a c++ impl from this post from stackoverflow and this implementation in python.我从 c++ impl 获得了来自 stackoverflow 的这篇文章和 python 中的这个实现的帮助。

But here I am not getting any output nor any error messages.但在这里我没有收到任何 output 或任何错误消息。

Note: using Rust v1.66.0-stable注意:使用Rust v1.66.0-stable

There are multiple things I would like to annotate about your code.我想对您的代码进行多处注释。

  • Don't hard-code a string through a manually specified &[u16] array.不要通过手动指定的&[u16]数组对字符串进行硬编码。 That's just absolutely impossible to read.那是绝对不可能阅读的。 Use a to_wstring() helper function and an actual string.使用to_wstring()帮助程序 function 和实际字符串。
  • You have to actually receive and process the messages.您必须实际接收和处理消息。 An empty loop does exactly what it should do: Nothing:) (and that with 100% CPU power)一个空循环完全按照它应该做的去做:什么都不做:)(并且 CPU 功率为 100%)
  • There is a return value check missing after CreateWindowExW , otherwise you would realize that this function fails. CreateWindowExW之后缺少返回值检查,否则你会意识到这个 function 失败了。
  • Why do you feed class_atom.into() into CreateWindowExW as the first argument?为什么将class_atom.into()作为第一个参数输入CreateWindowExW I couldn't find any reference what that would accomplish;我找不到任何参考资料可以完成什么; the first argument is dwExStyle , and class_atom is the class handle.第一个参数是dwExStyleclass_atom是 class 句柄。 Those have nothing in common;那些没有共同点; this is most likely the reason why CreateWindowExW fails.这很可能是CreateWindowExW失败的原因。 If at all, it should be the second argument, but as you already provide lpszClassName , you simply don't need the class atom.如果有的话,它应该是第二个参数,但是由于您已经提供lpszClassName ,所以您根本不需要 class 原子。
  • Avoid static mut in Rust. It's not thread-safe and requires unsafe to be accessed.避免static mut 。它不是线程安全的,需要unsafe才能访问。 Use AtomicBool instead.请改用AtomicBool

That said, here is a version that works for me:也就是说,这是一个适合我的版本:

use winapi::shared::minwindef::*;
use winapi::shared::windef::*;
use winapi::um::libloaderapi::*;
use winapi::um::winuser::*;

use std::ffi::OsStr;
use std::mem::zeroed;
use std::os::windows::ffi::OsStrExt;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;

fn to_wstring(s: &str) -> Vec<u16> {
    OsStr::new(s)
        .encode_wide()
        .chain(std::iter::once(0))
        .collect()
}

static ADDED_LISTENER: AtomicBool = AtomicBool::new(false);

pub unsafe extern "system" fn window_proc(
    hwnd: HWND,
    msg: UINT,
    wparam: WPARAM,
    lparam: LPARAM,
) -> LRESULT {
    println!("called {}", msg);

    match msg {
        WM_CREATE => {
            let add_result = AddClipboardFormatListener(hwnd);
            if add_result == 1 {
                ADDED_LISTENER.store(true, Ordering::Relaxed);
                0
            } else {
                -1
            }
        }
        WM_DESTROY => {
            if ADDED_LISTENER.swap(false, Ordering::Relaxed) {
                RemoveClipboardFormatListener(hwnd);
            }
            PostQuitMessage(0);
            0
        }
        WM_CLIPBOARDUPDATE => {
            println!("clipboard updated.");
            0
        }
        _ => DefWindowProcW(hwnd, msg, wparam, lparam),
    }
}

fn main() {
    unsafe {
        let hinst = GetModuleHandleW(std::ptr::null_mut());
        let wnd_class = WNDCLASSW {
            hInstance: hinst,
            lpfnWndProc: Some(window_proc),
            lpszClassName: to_wstring("ClipboardMessageWindow").as_ptr(),
            ..zeroed::<WNDCLASSW>()
        };
        if RegisterClassW(&wnd_class) == 0 {
            panic!("RegisterClassEx failed");
        }

        let hwnd = CreateWindowExW(
            0,
            wnd_class.lpszClassName,
            std::ptr::null(),
            0,
            0,
            0,
            0,
            0,
            HWND_MESSAGE,
            std::ptr::null_mut(),
            hinst,
            std::ptr::null_mut(),
        );
        if hwnd == std::ptr::null_mut() {
            panic!("CreateWindowEx failed");
        }

        let mut msg = std::mem::zeroed();
        loop {
            let res = GetMessageW(&mut msg, std::ptr::null_mut(), 0, 0);
            if res == 0 || res == -1 {
                break;
            }

            DispatchMessageW(&msg);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM