如何使用winapi机箱为Windows制作托盘图标?

如何使用winapi机箱为Windows制作托盘图标?,winapi,rust,trayicon,Winapi,Rust,Trayicon,我试图使用Rust的winapi板条箱制作一个简单的托盘图标。在C语言中我曾经尝试过,但是我不能让Rust高兴。稍后我将包含C代码,以显示我要使用的notifyiconda部分的哪些位 超基本目标: 让它说话 将其设置为如下所示的默认图标 这是最简单的;我可以在以后找出其他内置图标 更新单词 程序完成后将其删除 链接到Rust的winapi库(带有搜索功能!) 我真的一点也不懂Windows API,所以对我来说它完全是希腊语,我只是匹配我在其他示例中找到的语法,等等。所以请不要跳过任何

我试图使用Rust的winapi板条箱制作一个简单的托盘图标。在C语言中我曾经尝试过,但是我不能让Rust高兴。稍后我将包含C代码,以显示我要使用的
notifyiconda
部分的哪些位

超基本目标:

  • 让它说话

  • 将其设置为如下所示的默认图标

    这是最简单的;我可以在以后找出其他内置图标

  • 更新单词

  • 程序完成后将其删除

链接到Rust的winapi库(带有搜索功能!)

我真的一点也不懂Windows API,所以对我来说它完全是希腊语,我只是匹配我在其他示例中找到的语法,等等。所以请不要跳过任何内容,,因为我可能不知道其中隐含的内容(例如use std::或其他内容)

  • Rust版本1.3.1

  • winapi板条箱版本0.3.6

  • 视窗10

以下是我迄今为止管理的锈迹代码(但不起作用!):

下面是我试图模仿的C代码功能(不确定哪里需要什么库,所以我把它们大部分都放进去了):

#包括
#包括
#包括
#包括
#包括
#定义_WIN32_WINNT 0x0500//必须在windows.h之前,因为神秘的原因,例如widnows.h会用不正确的东西覆盖它
#包括
#包括//继续进行一些系统托盘工作
#为该托盘图标定义WM_MYMESSAGE(WM_USER+1)//
int main()
{
HWND HWND=GetConsoleWindow();//从https://stackoverflow.com/questions/11812095/hide-the-console-window-of-a-c-program 经由人类
NOTIFYICONDATA nid;//包含窗口信息和系统托盘内容的东西
nid.cbSize=sizeof(notifyiconda);//准备
nid.hWnd=hWnd;//链接控制台窗口
nid.uID=1001;//这是一个数字
nid.uCallbackMessage=WM_MYMESSAGE;//谁知道应该与单击捕获相关,但不是这样
nid.hIcon=LoadIcon(NULL,IDI_应用程序);//图标idk
strcpy(nid.szTip,“此处的工具提示文字”);//图标的工具提示
nid.szTip[19]='\0';//结尾处为null
nid.uFlags=NIF_消息| NIF_图标| NIF_提示;//谁知道呢
size_t nidszTipLength=sizeof(nid.szTip)/sizeof(nid.szTip[0]);//获取nid.szTip的大小(工具提示长度)
Shell_NotifyIcon(NIM_ADD,&nid);//显示图标
系统(“暂停”);
strcpy(nid.szTip,“更新的工具提示现在在这里!”;//图标的工具提示
Shell_NotifyIcon(NIM_MODIFY,&nid);//更新系统托盘图标
nid.szTip[31]='\0';//结尾处为null
系统(“暂停”);
Shell_NotifyIcon(NIM_DELETE,&nid);//完成后删除系统托盘图标
系统(“暂停”);
返回0;
}

我自己动手,找到了Rust中winapi的源代码,并获得了足够的帮助,成功地解决了这个问题。代码现在在语法上是有效的,这是一个奇妙的奖励

需要进行几次升级,主要是:

  • 将字符串转换为UTF-16格式,以便操作系统读取

  • 将该
    UTF-16
    写入128长
    uint16
    向量数组

  • unsafe{}
    之外创建
    nid
    ,以便在其他地方使用

  • 切换到winapi调用的W系列,而不是A系列(除了A系列需要一些奇怪的东西,比如
    int8
    而不是
    LoadIcon[letter]
    中的
    uint16
    之外,不确定它们之间的区别)

工作守则如下:

//-----Import Libraries (called crates)-----
extern crate winapi;
//-----Import Built-in Libraries (not called crates)-----
use std::process::Command; //use cmd.exe
use std::mem::{size_of, zeroed}; //get size of stuff and init with zeros
use std::ptr::null_mut; //use a null pointer (I think)
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

fn main()
{
// to navigate calling with the winapi "crate" use the search function at link
// https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/um/wincon/fn.GetConsoleWindow.html
let hWnd = unsafe { winapi::um::wincon::GetConsoleWindow }; //gets the current console window handle

//System Tray Icon support - here it is
let WM_MYMESSAGE = winapi::um::winuser::WM_APP + 100; //prep WM_MYMESSAGE
let mut trayToolTip = "Tool tip words here".to_string(); //record tooltip words for the icon
let mut trayToolTipInt: [u16; 128] = [0; 128]; //fill with 0's
let trayToolTipStrStep: &str = &*trayToolTip; //these two types of strings
let mut trayToolTipStepOS = OsStr::new(trayToolTipStrStep); //convert to OS string format or something
let mut trayToolTipStepUTF16 = trayToolTipStepOS.encode_wide().collect::<Vec<u16>>(); //now actually convert to UTF16 format for the OS
trayToolTipInt[..trayToolTipStepUTF16.len()].copy_from_slice(&trayToolTipStepUTF16); //record it in that nice integer holder

let mut nid: winapi::um::shellapi::NOTIFYICONDATAW = unsafe{ zeroed() }; //thing that has info on window and system tray stuff in it 
unsafe
{
    nid.cbSize = size_of::<winapi::um::shellapi::NOTIFYICONDATAW>() as u32; //prep
    nid.hWnd = hWnd(); //links the console window
    nid.uID = 1001; //it's a number
    nid.uCallbackMessage = WM_MYMESSAGE; //whoknows should be related to click capture but doesn't so
    nid.hIcon = winapi::um::winuser::LoadIconW(null_mut(), winapi::um::winuser::IDI_APPLICATION); //icon idk
    nid.szTip = trayToolTipInt; //tooltip for the icon
    nid.uFlags = winapi::um::shellapi::NIF_MESSAGE | winapi::um::shellapi::NIF_ICON | winapi::um::shellapi::NIF_TIP; //who knows
};

//let mut nidszTipLength = trayToolTip.chars().count() as u64; //gets the size of nid.szTip (tooltip length) indirectly (not the right size!)
let mut nidszTipLength = trayToolTipStepUTF16.len() as u64; //gets the size of nid.szTip (tooltip length) for the UTF-16 format, which is what Windows cares about

unsafe{ winapi::um::shellapi::Shell_NotifyIconW(winapi::um::shellapi::NIM_ADD, &mut nid) }; //shows the icon
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();

trayToolTip = "An updated tooltip is now here!".to_string(); //update the tooltip string
trayToolTipInt = [0; 128]; //fill with 0's (clear it out I hope)
let trayToolTipStrStep: &str = &*trayToolTip; //these two types of strings are hella annoying
trayToolTipStepOS = OsStr::new(trayToolTipStrStep); //convert to OS string format or something
trayToolTipStepUTF16 = trayToolTipStepOS.encode_wide().collect::<Vec<u16>>(); //now actually convert to UTF16 format for the OS
trayToolTipInt[..trayToolTipStepUTF16.len()].copy_from_slice(&trayToolTipStepUTF16); //record it in that nice integer holder
nid.szTip = trayToolTipInt; //tooltip for the icon
//nidszTipLength = trayToolTip.chars().count() as u64; //gets the size of nid.szTip (tooltip length) indirectly (not the right size!)
nidszTipLength = trayToolTipStepUTF16.len() as u64; //gets the size of nid.szTip (tooltip length) for the UTF-16 format, which is what Windows cares about
unsafe{ winapi::um::shellapi::Shell_NotifyIconW(winapi::um::shellapi::NIM_MODIFY, &mut nid) }; //updates system tray icon

let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();

unsafe{ winapi::um::shellapi::Shell_NotifyIconW(winapi::um::shellapi::NIM_DELETE, &mut nid) }; //deletes system tray icon when done

let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();

}

那么uCallbackMessage=WM_MYMESSAGE呢?从下面的C代码来看,它只是
WM\u USER+1
。考虑到窗口是一个控制台,
WM_USER+X
将由窗口类的创建者定义,这可能不是一个明智的选择,但是嘿,这只是一个测试,不是吗?事实上,只是一个测试!我也不知道如何在Rust中实现
WM_MYMESSAGE
,因此这是计划中的额外障碍。似乎
WM_USER+X
只是一系列私有消息值-在接下来的几千年中,是否最好抛开WM_USER+10000并避免冲突(我看到最大值为7FFF==32767)?当然,如果我对模糊文档理解正确的话。请回顾如何创建一个模糊文档,然后你的问题将其包括在内。您的锈迹代码在语法上无效。试着制造一些能再现你在网络上的错误的东西,或者你可以在一个全新的货运项目中再现它。也有。正确的方法是注册您自己的窗口类,然后您可以自由定义
WM_USER+X
。如果您使用其他人的窗口类,那么最好使用
WM_APP+X
或者更好的
RegisterWindowMessage()
@rodrigo感谢您的深入了解,我将切换到
WM_APP
!从文档来看,似乎有2个以上的应用程序在处理同一条消息,所以我将远离这里——这里是简单的1个应用程序@Shepmaster对于req范围来说是最小的。但我跟你们说的很清楚,这在语法上是不合法的,因为我不知道怎么做。因此,我们来到这里。
'NOTIFYICONDATAA
在Rust中需要我不想提供的输入-许多语法上奇妙的障碍中的第一个!
[target.'cfg(windows)'.dependencies]
winapi = { version = "*", features = ["wincon","shellapi","ntdef"] }
//-----Import Libraries (called crates)-----
extern crate winapi;
//-----Import Built-in Libraries (not called crates)-----
use std::process::Command; //use cmd.exe
use std::mem::{size_of, zeroed}; //get size of stuff and init with zeros
use std::ptr::null_mut; //use a null pointer (I think)
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;

fn main()
{
// to navigate calling with the winapi "crate" use the search function at link
// https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/um/wincon/fn.GetConsoleWindow.html
let hWnd = unsafe { winapi::um::wincon::GetConsoleWindow }; //gets the current console window handle

//System Tray Icon support - here it is
let WM_MYMESSAGE = winapi::um::winuser::WM_APP + 100; //prep WM_MYMESSAGE
let mut trayToolTip = "Tool tip words here".to_string(); //record tooltip words for the icon
let mut trayToolTipInt: [u16; 128] = [0; 128]; //fill with 0's
let trayToolTipStrStep: &str = &*trayToolTip; //these two types of strings
let mut trayToolTipStepOS = OsStr::new(trayToolTipStrStep); //convert to OS string format or something
let mut trayToolTipStepUTF16 = trayToolTipStepOS.encode_wide().collect::<Vec<u16>>(); //now actually convert to UTF16 format for the OS
trayToolTipInt[..trayToolTipStepUTF16.len()].copy_from_slice(&trayToolTipStepUTF16); //record it in that nice integer holder

let mut nid: winapi::um::shellapi::NOTIFYICONDATAW = unsafe{ zeroed() }; //thing that has info on window and system tray stuff in it 
unsafe
{
    nid.cbSize = size_of::<winapi::um::shellapi::NOTIFYICONDATAW>() as u32; //prep
    nid.hWnd = hWnd(); //links the console window
    nid.uID = 1001; //it's a number
    nid.uCallbackMessage = WM_MYMESSAGE; //whoknows should be related to click capture but doesn't so
    nid.hIcon = winapi::um::winuser::LoadIconW(null_mut(), winapi::um::winuser::IDI_APPLICATION); //icon idk
    nid.szTip = trayToolTipInt; //tooltip for the icon
    nid.uFlags = winapi::um::shellapi::NIF_MESSAGE | winapi::um::shellapi::NIF_ICON | winapi::um::shellapi::NIF_TIP; //who knows
};

//let mut nidszTipLength = trayToolTip.chars().count() as u64; //gets the size of nid.szTip (tooltip length) indirectly (not the right size!)
let mut nidszTipLength = trayToolTipStepUTF16.len() as u64; //gets the size of nid.szTip (tooltip length) for the UTF-16 format, which is what Windows cares about

unsafe{ winapi::um::shellapi::Shell_NotifyIconW(winapi::um::shellapi::NIM_ADD, &mut nid) }; //shows the icon
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();

trayToolTip = "An updated tooltip is now here!".to_string(); //update the tooltip string
trayToolTipInt = [0; 128]; //fill with 0's (clear it out I hope)
let trayToolTipStrStep: &str = &*trayToolTip; //these two types of strings are hella annoying
trayToolTipStepOS = OsStr::new(trayToolTipStrStep); //convert to OS string format or something
trayToolTipStepUTF16 = trayToolTipStepOS.encode_wide().collect::<Vec<u16>>(); //now actually convert to UTF16 format for the OS
trayToolTipInt[..trayToolTipStepUTF16.len()].copy_from_slice(&trayToolTipStepUTF16); //record it in that nice integer holder
nid.szTip = trayToolTipInt; //tooltip for the icon
//nidszTipLength = trayToolTip.chars().count() as u64; //gets the size of nid.szTip (tooltip length) indirectly (not the right size!)
nidszTipLength = trayToolTipStepUTF16.len() as u64; //gets the size of nid.szTip (tooltip length) for the UTF-16 format, which is what Windows cares about
unsafe{ winapi::um::shellapi::Shell_NotifyIconW(winapi::um::shellapi::NIM_MODIFY, &mut nid) }; //updates system tray icon

let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();

unsafe{ winapi::um::shellapi::Shell_NotifyIconW(winapi::um::shellapi::NIM_DELETE, &mut nid) }; //deletes system tray icon when done

let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();

}
[target.'cfg(windows)'.dependencies]
winapi = { version = "*", features = ["winuser","wincon","shellapi"] }