如何使用 winapi crate 为 Windows 制作托盘图标?
How to make a tray icon for Windows using the winapi crate?
我正在尝试使用 Rust 的 winapi crate 制作一个简单的托盘图标。我以前在 C 中设法做到了,但我不能让 Rust 开心。稍后我将包含 C 代码以显示我想使用的 NOTIFYICONDATA
部分的哪些位。
超级基本目标:
让它说话
让它成为这样的默认图标
这是最简单的;其他的内置图标以后再想吧
更新单词
程序结束后删除
Link到Rust的winapi库(带搜索功能!)
https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/um/wincon/fn.GetConsoleWindow.html
我真的根本不知道 Windows API,所以这对我来说都是希腊语,我只是匹配我在其他示例等中找到的语法。所以请不要跳过任何东西,因为我可能不知道那里隐含了什么(例如使用 std:: 或其他东西)!
Rust 版本 1.3.1
winapi crate 版本 0.3.6
Windows 10
这是我目前管理的 Rust 代码(但不起作用!):
//-----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; //get size of stuff
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"; //record tooltip words for the icon
let nid = winapi::um::shellapi::NOTIFYICONDATAA //thing that has info on window and system tray stuff in it
{
cbSize: size_of::<winapi::um::shellapi::NOTIFYICONDATAA>() as u32, //prep
hWnd: hWnd(), //links the console window
uID: 1001, //it's a number
uCallbackMessage: WM_MYMESSAGE, //whoknows should be related to click capture but doesn't so
//Couldn't find anything for WM_MYMESSAGE at all
hIcon: winapi::um::winuser::LoadIconA(winapi::shared::ntdef::NULL, winapi::um::winuser::IDI_APPLICATION), //icon idk
szTip: trayToolTip, //tooltip for the icon
uFlags: winapi::um::shellapi::NIF_MESSAGE | winapi::um::shellapi::NIF_ICON | winapi::um::shellapi::NIF_TIP, //who knows
};
let nidszTipLength: u64 = szTip.chars().count(); //gets the size of nid.szTip (tooltip length)
winapi::um::shellapi::Shell_NotifyIconA(winapi::um::shellapi::NIM_ADD, &nid); //shows the icon
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
nid.szTip: "An updated tooltip is now here!"; //tooltip for the icon
//abs total guess hoping some Python . stuff that I see sometimes in Rust works here and maybe it gets a : instead of a = too
winapi::um::shellapi::Shell_NotifyIconA(winapi::um::shellapi::NIM_MODIFY, &nid); //updates system tray icon
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
winapi::um::shellapi::Shell_NotifyIconA(winapi::um::shellapi::NIM_DELETE, &nid); //deletes system tray icon when done
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
}
Cargo.toml 需要这个:
[target.'cfg(windows)'.dependencies]
winapi = { version = "*", features = ["wincon","shellapi","ntdef"] }
这里是我试图模仿的 C 代码功能(不确定需要哪些库,所以我将其中的大部分放入其中):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#define _WIN32_WINNT 0x0500 //must be before windows.h for mystical reasons such as widnows.h overwrites it with not right thing
#include <windows.h>
#include <shellapi.h> // make some system tray stuff go on
#define WM_MYMESSAGE (WM_USER + 1) //for that tray icon
int main()
{
HWND hWnd = GetConsoleWindow(); // from via Anthropos
NOTIFYICONDATA nid; //thing that has info on window and system tray stuff in it
nid.cbSize = sizeof(NOTIFYICONDATA); //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 = LoadIcon(NULL, IDI_APPLICATION); //icon idk
strcpy(nid.szTip, "Tool tip words here"); //tooltip for the icon
nid.szTip[19] = '[=13=]'; //null at the end of it
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; //who knows
size_t nidszTipLength = sizeof(nid.szTip) / sizeof(nid.szTip[0]); //gets the size of nid.szTip (tooltip length)
Shell_NotifyIcon(NIM_ADD, &nid); //shows the icon
system("pause");
strcpy(nid.szTip, "An updated tooltip is now here!"); //tooltip for the icon
Shell_NotifyIcon(NIM_MODIFY, &nid); //updates system tray icon
nid.szTip[31] = '[=13=]'; //null at the end of it
system("pause");
Shell_NotifyIcon(NIM_DELETE, &nid); //deletes system tray icon when done
system("pause");
return 0;
}
我独自出击,前往 Rust https://github.com/retep998/winapi-rs/issues/725 中 winapi 的源代码,并获得了足够的帮助,成功地解决了这个问题。代码现在 语法有效 作为一个奇妙的奖励!
需要进行一些升级,主要是:
将字符串转换为 UTF-16
格式,以便 OS 读取
将UTF-16
写入一个128长的uint16
向量数组
在 unsafe{ }
之外创建 nid
以便它可以在其他地方使用
切换到 W 系列的 winapi 调用而不是 A 系列(不确定 A 系列以外的区别想要奇怪的东西,比如 int8
而不是 uint16
在 LoadIcon[letter]
)
工作代码如下:
//-----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();
}
并且不要忘记在您的 Cargo.toml
中包含以下内容!
[target.'cfg(windows)'.dependencies]
winapi = { version = "*", features = ["winuser","wincon","shellapi"] }
我正在尝试使用 Rust 的 winapi crate 制作一个简单的托盘图标。我以前在 C 中设法做到了,但我不能让 Rust 开心。稍后我将包含 C 代码以显示我想使用的 NOTIFYICONDATA
部分的哪些位。
超级基本目标:
让它说话
让它成为这样的默认图标
这是最简单的;其他的内置图标以后再想吧
更新单词
程序结束后删除
Link到Rust的winapi库(带搜索功能!)
https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/um/wincon/fn.GetConsoleWindow.html
我真的根本不知道 Windows API,所以这对我来说都是希腊语,我只是匹配我在其他示例等中找到的语法。所以请不要跳过任何东西,因为我可能不知道那里隐含了什么(例如使用 std:: 或其他东西)!
Rust 版本 1.3.1
winapi crate 版本 0.3.6
Windows 10
这是我目前管理的 Rust 代码(但不起作用!):
//-----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; //get size of stuff
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"; //record tooltip words for the icon
let nid = winapi::um::shellapi::NOTIFYICONDATAA //thing that has info on window and system tray stuff in it
{
cbSize: size_of::<winapi::um::shellapi::NOTIFYICONDATAA>() as u32, //prep
hWnd: hWnd(), //links the console window
uID: 1001, //it's a number
uCallbackMessage: WM_MYMESSAGE, //whoknows should be related to click capture but doesn't so
//Couldn't find anything for WM_MYMESSAGE at all
hIcon: winapi::um::winuser::LoadIconA(winapi::shared::ntdef::NULL, winapi::um::winuser::IDI_APPLICATION), //icon idk
szTip: trayToolTip, //tooltip for the icon
uFlags: winapi::um::shellapi::NIF_MESSAGE | winapi::um::shellapi::NIF_ICON | winapi::um::shellapi::NIF_TIP, //who knows
};
let nidszTipLength: u64 = szTip.chars().count(); //gets the size of nid.szTip (tooltip length)
winapi::um::shellapi::Shell_NotifyIconA(winapi::um::shellapi::NIM_ADD, &nid); //shows the icon
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
nid.szTip: "An updated tooltip is now here!"; //tooltip for the icon
//abs total guess hoping some Python . stuff that I see sometimes in Rust works here and maybe it gets a : instead of a = too
winapi::um::shellapi::Shell_NotifyIconA(winapi::um::shellapi::NIM_MODIFY, &nid); //updates system tray icon
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
winapi::um::shellapi::Shell_NotifyIconA(winapi::um::shellapi::NIM_DELETE, &nid); //deletes system tray icon when done
let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
}
Cargo.toml 需要这个:
[target.'cfg(windows)'.dependencies]
winapi = { version = "*", features = ["wincon","shellapi","ntdef"] }
这里是我试图模仿的 C 代码功能(不确定需要哪些库,所以我将其中的大部分放入其中):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#define _WIN32_WINNT 0x0500 //must be before windows.h for mystical reasons such as widnows.h overwrites it with not right thing
#include <windows.h>
#include <shellapi.h> // make some system tray stuff go on
#define WM_MYMESSAGE (WM_USER + 1) //for that tray icon
int main()
{
HWND hWnd = GetConsoleWindow(); // from via Anthropos
NOTIFYICONDATA nid; //thing that has info on window and system tray stuff in it
nid.cbSize = sizeof(NOTIFYICONDATA); //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 = LoadIcon(NULL, IDI_APPLICATION); //icon idk
strcpy(nid.szTip, "Tool tip words here"); //tooltip for the icon
nid.szTip[19] = '[=13=]'; //null at the end of it
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; //who knows
size_t nidszTipLength = sizeof(nid.szTip) / sizeof(nid.szTip[0]); //gets the size of nid.szTip (tooltip length)
Shell_NotifyIcon(NIM_ADD, &nid); //shows the icon
system("pause");
strcpy(nid.szTip, "An updated tooltip is now here!"); //tooltip for the icon
Shell_NotifyIcon(NIM_MODIFY, &nid); //updates system tray icon
nid.szTip[31] = '[=13=]'; //null at the end of it
system("pause");
Shell_NotifyIcon(NIM_DELETE, &nid); //deletes system tray icon when done
system("pause");
return 0;
}
我独自出击,前往 Rust https://github.com/retep998/winapi-rs/issues/725 中 winapi 的源代码,并获得了足够的帮助,成功地解决了这个问题。代码现在 语法有效 作为一个奇妙的奖励!
需要进行一些升级,主要是:
将字符串转换为
UTF-16
格式,以便 OS 读取将
UTF-16
写入一个128长的uint16
向量数组在
unsafe{ }
之外创建nid
以便它可以在其他地方使用切换到 W 系列的 winapi 调用而不是 A 系列(不确定 A 系列以外的区别想要奇怪的东西,比如
int8
而不是uint16
在LoadIcon[letter]
)
工作代码如下:
//-----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();
}
并且不要忘记在您的 Cargo.toml
中包含以下内容!
[target.'cfg(windows)'.dependencies]
winapi = { version = "*", features = ["winuser","wincon","shellapi"] }