tray 库是使用 c99 实现的跨平台系统托盘程序库。本文将尝试使用 Rust 调用它。

首先,使用 bindgen 将头文件转换成 Rust 调用声明:

bindgen tray.h -o src/tray.rs

从生成的文件可以看到,只生成了对应的结构体而没有生成相应的函数,这是因为里面的函数被标记为 static。想了解更高的建议检索关键字「c语言 static」。于是,在 c_tray.h 中手动导出这些函数:

#ifndef C_TRAY_H
#define C_TRAY_H

#include "tray.h"

int c_tray_init(struct tray *tray);
int c_tray_loop(int blocking);
void c_tray_update(struct tray *tray);
void c_tray_exit();

#endif /* C_TRAY_H */

并在 c_tray.c 中实现这些函数:

#if defined(_WIN32) || defined(_WIN64)
#define TRAY_WINAPI 1
#elif defined(__linux__) || defined(linux) || defined(__linux)
#define TRAY_APPINDICATOR 1
#elif defined(__APPLE__) || defined(__MACH__)
#define TRAY_APPKIT 1
#endif

#include "c_tray.h"

int c_tray_init(struct tray *tray) { return tray_init(tray); }
int c_tray_loop(int blocking) { return tray_loop(blocking); }
void c_tray_update(struct tray *tray) { return tray_update(tray); }
void c_tray_exit() { return tray_exit(); }

再次生成:

bindgen c_tray.h -o src/tray.rs

编写生成脚本 build.rs

fn main() {
    cc::Build::new()
        .file("c_tray.c")
        .compile("c_tray");

    println!("cargo:rustc-link-lib=User32");
    println!("cargo:rustc-link-lib=Shell32");
}

使用示例:

use std::ffi::CString;

mod tray;


unsafe extern "C" fn calliit(menu: *mut tray::tray_menu) {
    println!("{:?}", menu);
    tray::c_tray_exit();
}

unsafe extern "C" fn hello(menu: *mut tray::tray_menu) {
    println!("{:?}", menu);
    println!("{:?}", "Hello");
}

fn main() {
    unsafe {
        let text = CString::new("Hello").unwrap();
        let text2 = CString::new("Exit").unwrap();

        let mut menu = [
            tray::tray_menu {
                text: text.as_ptr() as *mut libc::c_char,
                disabled: 0,
                checked: 0,
                cb: Some(hello),
                context: std::ptr::null_mut(),
                submenu: std::ptr::null_mut(),
            },
            tray::tray_menu {
                text: text2.as_ptr() as *mut libc::c_char,
                disabled: 0,
                checked: 0,
                cb: Some(calliit),
                context: std::ptr::null_mut(),
                submenu: std::ptr::null_mut(),
            },
            tray::tray_menu {
                text: text2.as_ptr() as *mut libc::c_char,
                disabled: 0,
                checked: 0,
                cb: Some(calliit),
                context: std::ptr::null_mut(),
                submenu: std::ptr::null_mut(),
            }
        ];
        

        let icon = CString::new("icon.ico").unwrap();
        let mut trayy = tray::tray {
            icon: icon.as_ptr() as *mut libc::c_char,
            menu: menu.as_mut_ptr().cast(),
        };

        tray::c_tray_init(&mut trayy as *mut tray::tray);

        // std::mem::forget(trayy);
        while tray::c_tray_loop(1) == 0 {}
    }
}
最后修改:2024 年 03 月 02 日
如果觉得我的文章对你有用,请随意赞赏