Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add icon to binary file #9

Closed
MrTanoshii opened this issue Sep 22, 2022 · 19 comments · Fixed by #25
Closed

Add icon to binary file #9

MrTanoshii opened this issue Sep 22, 2022 · 19 comments · Fixed by #25
Assignees
Labels
enhancement New feature or request

Comments

@MrTanoshii
Copy link
Owner

MrTanoshii commented Sep 22, 2022

Problem

The app icon is currently implemented in the app itself but not on the binary file.

explorer_2y9u6T4fld

Potential Solutions

@MrTanoshii MrTanoshii added enhancement New feature or request help wanted Extra attention is needed hacktoberfest https://hacktoberfest.com/ and removed help wanted Extra attention is needed labels Sep 22, 2022
@bryonye
Copy link

bryonye commented Sep 26, 2022

Hi, I’m interested in having a go at this!

@MrTanoshii
Copy link
Owner Author

MrTanoshii commented Sep 26, 2022

Hi, I’m interested in having a go at this!

Of course, you are very much welcome to do so!
Thank you for the interest.

I had been looking into it lately too, I think winres will not work out after all as Rusty AutoClicker uses rust-version = "1.63" and there is a an open issue mxre/winres#40 starting from 1.61

Another crate to look into is https://crates.io/crates/embed-resource (Windows).
I haven't found any potential solutions for Linux and macOS.

Edit: Linux executables do not have icons

@MrTanoshii
Copy link
Owner Author

@bryonye Are you still interested in this?

@MrTanoshii MrTanoshii removed the hacktoberfest https://hacktoberfest.com/ label Nov 6, 2022
@MrTanoshii MrTanoshii removed this from the Hacktoberfest 2022 milestone Nov 6, 2022
@MrTanoshii
Copy link
Owner Author

@nozwock
Copy link
Contributor

nozwock commented Nov 6, 2022

@MrTanoshii Hey how's it going? I just looked up your profile and found this, Would you like me to submit a PR for this? If you haven't made the changes already that is.

Regarding macOS, I think I've read before on how to add an Icon to a macOS binary (will have to look that up again) but I don't really have an access to a macOS, so can't really test it out.

@MrTanoshii
Copy link
Owner Author

Yes, if you're up for it please do submit a PR.
It will be very welcome!

I'm assigning this to you

@nozwock
Copy link
Contributor

nozwock commented Nov 6, 2022

Alright, I'll submit it tomorrow. It's late here rn.

@nozwock
Copy link
Contributor

nozwock commented Nov 7, 2022

Hey @MrTanoshii, I wanted to confirm something; Why do we've a lib crate in this package?
Am I missing something? Because to me It makes not much sense to have a lib crate here.

The reason I'm mentioning this is because unfortunately winres doesn't work with packages having both a lib crate and bin crate, as mentioned here mxre/winres#32 (comment) (seems to be due to cargo limitations).

Some possible solutions:

  1. Get rid of lib.rs and then use winres. (very straightforward to do, overkill?)
  2. Dividing the pkg into different pkgs (with cargo workspaces) and then make use of the lib pkg in the bin pkg. (overkill?)
  3. Just have something like rcedit apply the resources after the build process (can be automated for eg. with CI).
  4. Explore some other options like the embed-resource for instance.

@nozwock
Copy link
Contributor

nozwock commented Nov 7, 2022

And coming to Icons, should I just use the existing icon-64x64.ico or rather make a new .ico of higher res (like 256x256 or 512x512)?

@MrTanoshii
Copy link
Owner Author

#25 (comment)

Let's go with 256x256

@MrTanoshii MrTanoshii linked a pull request Nov 7, 2022 that will close this issue
@ITachiLab
Copy link

ITachiLab commented Nov 7, 2022

Hey, just to let you know that I successfully forced resources to be added to the binary crate in a project with both library and binary crate. You can check my workaround there: mxre/winres#32 (comment).

I'm not involved in this project, but removing lib.rs is slight overkill imho. Even in the official documentation authors of Rust suggest dividing application into binary and library crates.

@nozwock
Copy link
Contributor

nozwock commented Nov 8, 2022

I'm not involved in this project, but removing lib.rs is slight overkill imho. Even in the official documentation authors of Rust suggest dividing application into binary and library crates.

Hi @ITachiLab, It's not that I wanted to remove lib.rs just for the sake of making winres work, but also that I didn't get the point of having a lib.rs here. We can just have functionalities divided into modules, can't we? What's wrong with that approach?
Also, it just feels weird to me to have app.rs as part of a lib crate.

Actually I'm new to rust, so it'd be great if you could let me know your thoughts on this. I guess this is probably already have been discussed in some later chapter of the Rust book, which I'm currently going through.

Thanks for mentioning the workaround btw, I'll look into it.

@nozwock
Copy link
Contributor

nozwock commented Nov 8, 2022

Oh @ITachiLab actually, I remember trying that workaround before I removed the lib crate. It didn't workout on my end unfortunately; using Rust 1.64 and this winres fork.

I guess I'll try it again, just to be sure.

Edit: tried again, didn't work (doesn't work with cdylib either, just gives different error)

Compiling rusty-autoclicker v2.1.0 (/home/nozwock/hub/dev/forks/rusty-autoclicker)
error: the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs

error: could not compile `rusty-autoclicker` due to previous error

Here's the build.rs

use std::io;
use winres::WindowsResource;

fn main() -> io::Result<()> {
    if std::env::var("CARGO_CFG_TARGET_FAMILY").unwrap() == "windows" {
        let mut res = WindowsResource::new();
        let env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap();
        match env.as_str() {
            "gnu" => {
                res.set_ar_path("x86_64-w64-mingw32-ar")
                    .set_windres_path("x86_64-w64-mingw32-windres");
            }
            "msvc" => {}
            _ => panic!("unsupported target-env: {}", env),
        };
        res.set_icon("assets/icon-256.ico");
        res.compile()?;
        println!("cargo:rustc-link-arg-bins=resource.lib");
    }
    Ok(())
}

Hmm, I was using x86_64-pc-windows-gnu target, maybe this would work fine with x86_64-pc-windows-msvc but I don't have a windows machine right now to test it.

@ITachiLab
Copy link

Hmm, I was using x86_64-pc-windows-gnu target, maybe this would work fine with x86_64-pc-windows-msvc but I don't have a windows machine right now to test it.

From what I can see in winres source code here: https://github.com/mxre/winres/blob/master/lib.rs#L597, when using GNU tools for compiling, winres creates libresource.a instead of resource.lib, which is understandable because .lib format is used only by Windows.

With that being said, you can try using one of these for the GNU tools:

println!("cargo:rustc-link-arg-bins=libresource.a");
println!("cargo:rustc-link-arg-bins=-lresource");

Actually I'm new to rust

No worries, me too 😅.

@nozwock
Copy link
Contributor

nozwock commented Nov 9, 2022

winres creates libresource.a instead of resource.lib, which is understandable because .lib format is used only by Windows.

Didn't thought of that.

println!("cargo:rustc-link-arg-bins=-lresource");

This works (with original winres & Rust 1.65), mxre/winres#40 (comment). Don't know what the windows equivalent for this would be, since I don't know anything about linking flags.

#[cfg(unix)]
{
    println!("cargo:rustc-link-arg=-Wl,--whole-archive");
    println!("cargo:rustc-link-arg=-Wl,-Bstatic");
    println!("cargo:rustc-link-arg-bins=-lresource");
    println!("cargo:rustc-link-arg=-Wl,--no-whole-archive");
}

@ITachiLab
Copy link

ITachiLab commented Nov 9, 2022

For Windows and MSVC, having just println!("cargo:rustc-link-arg-bins=resource.lib"); is enough. I'm currently developing a Windows application under Windows and already had gone through the same problem of including resources. https://github.com/ITachiLab/rectangular/blob/master/build.rs#L8

Apparently, MSVC expects resources to appear in linker command line and knows how to deal with them without additional flags.

@nozwock
Copy link
Contributor

nozwock commented Nov 9, 2022

For Windows and MSVC, having just println!("cargo:rustc-link-arg-bins=resource.lib"); is enough. I'm currently developing a Windows application under Windows and already had gone through the same problem of including resources. https://github.com/ITachiLab/rectangular/blob/master/build.rs#L8

I see, got it, Thanks!

btw @ITachiLab, I've looked up your project rectangular and it looks like it's completely related to the windows platform. Sorry for being a bother and this is getting off topic but I was hoping maybe you could help me with this Rust windows related issue (nozwock/ventoy-toybox#1) of mine.

TL;DR I need to launch an .exe as a subprocess with elevated privileges (using UAC prompt) & process pwd set to parent directory of the .exe.

While searching I came across this post "how do I trigger a new process to be run as admin?".
The API version being used there seems to be quite old 0.10 and also is unsafe necessary for this case? Any advice on how to approach this?

@ITachiLab
Copy link

No worries, we both learn by solving issues ^^.

The API version being used there seems to be quite old 0.10

It's waaaay outdated. The latest version of windows crate is 0.43.0, this is the version I'm using for Rectangular.

So, in order to run an executable as an administrator, you indeed must use ShellExecuteA function from Windows API. When working with Rust and Windows API, always browse two things simultaneously, the first and foremost is a documentation for Windows API itself, in our case this will be a page dedicated to ShellExecuteA: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea; the second is a documentation for the analogous function in windows crate: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/Shell/fn.ShellExecuteA.html. The crate for Windows stuff is developed by guys from Microsoft, so it's always in sync with Windows API. The crate documentation is rather laconic, but the most important thing is the search bar which you will be using for determining in which module the function lives, and information what features you must include to use the function.

Putting this all together, Cargo.toml:

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

main.rs:

use windows::{
    s, Win32::UI::Shell::ShellExecuteA, Win32::Foundation::GetLastError,
    Win32::UI::WindowsAndMessaging::SW_NORMAL
};

fn main() {
    unsafe {
        let result = ShellExecuteA(
            None,
            s!("runas"),
            s!("C:\\Users\\Itachi\\AppData\\Local\\Programs\\Python\\Python38-32\\python.exe"),
            s!("-c \"import os; os.mkdir('test');\""),
            s!("C:\\Users\\Administrator"),
            SW_NORMAL
        );

        println!("{}", GetLastError().0);
    }
    
    assert!(result.0 > 32);
}

What I'm doing here is running Python as an Administrator, setting C:\Users\Administrator as the working directory, and I'm passing a simple script to the interpreter; the script simply creates a 'test' directory within the working directory. I ran this program successfully, UAC asked for permissions and the directory has been created in Administrator's home directory, which means it truly has started with correct permissions.

@nozwock
Copy link
Contributor

nozwock commented Nov 10, 2022

@ITachiLab Thanks a lot!
I got it to work through your examples.

nozwock/ventoy-toybox#6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants