如何将图标链接到Rust Windows应用程序

k5hmc34c  于 2023-01-09  发布在  Windows
关注(0)|答案(2)|浏览(338)

在Rust桌面应用程序中,总是使用窗口struct的某个版本,例如WNDCLASSW。当定义WNDCLASSW时,可以通过struct成员hIcon添加 * 类图标 *。下面的代码摘录演示了如何包括存储在文件Icon.ico中的图标。

...
        let hicon: HICON = LoadImageW(
            0 as HINSTANCE, 
            wide_null("Icon.ico").as_ptr(), 
            IMAGE_ICON, 0, 0, LR_LOADFROMFILE
        ) as HICON;

        let hinstance = GetModuleHandleW(null_mut());

        let mut wc: WNDCLASSW = std::mem::zeroed();
        wc.lpfnWndProc = Some(window_proc);
        wc. hInstance = hinstance;
        wc.hIcon = hicon;
        wc.lpszClassName = name.as_ptr();
...

图标文件在程序执行过程中加载,并且必须存储在与exe文件相同的文件夹中。如果缺少图标文件,LoadImageW()将返回NULL句柄。将hIcon设置为NULL是有效的,并且会导致使用标准系统图标。
虽然这种方法产生了所需的图标,但图标文件是在执行过程中加载的,并且必须与exe文件沿着交付。该图标应链接到exe文件并在其中传送。
如何将图标链接到Rust Windows应用程序并在那里使用它?
我知道this solution,但它在编译过程中生成了数千行错误和警告,必须被视为过时。This solution可以工作,但它只添加了Windows File Explorer中显示的 *exe图标 *,而 *class图标 *(在任务栏中)没有改变。在互联网上可以找到 *exe图标 * 的其他几种解决方案,但这不是我要找的。

jum4pzuy

jum4pzuy1#

在Windows上将资源嵌入到可执行映像中的标准过程是编写一个resource file(.rc),让resource compiler将其转换为二进制表示,并将其传递给链接器。
由于与Cargo中的链接器交互有些繁琐,因此使用现有的crate来处理这个问题要容易一些。正如您所发现的,有winres(看起来有点过时),所以我在这里将使用embed-resource
如果您想沿着,请从创建一个新的二进制crate开始

cargo new --bin embed_icon

接下来,将您选择的图标复制到机箱的根目录中(我使用的是从here下载的“rust_lang_logo.ico”),并在同一位置创建资源脚本(embed_icon.rc):
所有这一切只是告诉资源编译器它应该查找一个名为"rust_lang_logo.ico"的图标,并在生成其二进制输出时为其分配一个ID 1。
我们当然需要一个货物。

[package]
name = "embed_icon"
version = "0.0.0"
edition = "2021"

[dependencies.windows]
version = "0.43.0"
features = [
    "Win32_Foundation",
    "Win32_UI_WindowsAndMessaging",
    "Win32_System_LibraryLoader",
]

[build-dependencies]
embed-resource = "1.8"

这里声明了我们将要使用的windows特性,并将嵌入式资源作为 build 依赖项导入。main.rs

use windows::{
    core::{Result, PCWSTR},
    Win32::{
        System::LibraryLoader::GetModuleHandleW,
        UI::WindowsAndMessaging::{LoadImageW, IMAGE_ICON, LR_DEFAULTSIZE},
    },
};

fn main() -> Result<()> {
    let _icon = unsafe {
        LoadImageW(
            GetModuleHandleW(None)?,
            PCWSTR(1 as _), // Value must match the `nameID` in the .rc script
            IMAGE_ICON,
            0,
            0,
            LR_DEFAULTSIZE,
        )
    }?;

    Ok(())
}

这并没有做太多的事情,除了尝试加载我们刚刚嵌入到二进制文件中的图标。
错误:错误{代码:HRESULT(0x 80070714),消息:“指定的映像文件不包含资源节。”}
和一个二进制文件,在文件资源管理器中如下所示:

最后一步是实际运行embed-resource并将图标链接到可执行文件映像中。为此需要一个build script。要添加一个build script,请build.rs在crate的根目录中创建一个名为“www.example.com“的文件,其内容如下:

fn main() {
    embed_resource::compile("embed_icon.rc");
}

这就很好地把所有的东西整合在一起了。现在运行可执行文件是成功的,当二进制文件显示在文件资源管理器中时,它有一个漂亮的图标:

  • 注:* 上述解决方案使用windows机箱,其设计目的是为了方便和更好的安全性。如果您使用winapiwindows-sys机箱,核心原理仍然相同。但www.example.com中的代码main.rs必须进行调整。
2mbi3lxu

2mbi3lxu2#

本文通过IInspectable补充了Answer 1,为winapi的用户添加了信息。
按照答案1中的描述创建资源文件<name>.rcbuild.rs,并将这些文件与图标文件<name>.ico沿着放在项目根目录中。将构建依赖项添加到Cargo.toml中的embed-resource。使用这些更改构建的应用程序exe文件将嵌入图标文件中的图标。
要更改任务栏中显示的 class icon,请按如下所示设置WNDCLASSW中的hIcon成员:

hIcon = LoadImageW( 
    GetModuleHandleW(0 as LPCWSTR), // hInst; the .exe file
    MAKEINTRESOURCEW( 1 ),          // name; use the resource number in the .rc file
    IMAGE_ICON,                     // type
    0,                              // cx
    0,                              // cy
    0                               // fuLoad
    ) as HICON;

相关问题