Error: Error calling dlltool 'dlltool.exe': program not found

I am trying to write a simple program using Windows API like that:

extern crate windows_link;

fn main() {
    windows_link::link!("kernel32.dll" "system" fn SetLastError(code: u32));
    windows_link::link!("kernel32.dll" "system" fn GetLastError() -> u32);
    
    unsafe {
        SetLastError(1234);
        assert_eq!(GetLastError(), 1234);
    }
}

However I am getting:

error: Error calling dlltool 'dlltool.exe': program not found

error: aborting due to 1 previous error

Rust programs not using Windows API are compiled and run fine.

is there any reason you are using windows-link insead of windows-targets?

are you using the -windows-gnu toolchain? make sure the rust-mingw component is installed, it should contain a dlltool.

[quote="nerditation, post:2, topic:124236"]
are you using the -windows-gnu toolchain?
[/quote] Yes, I am. Otherwise I am getting a link error.

There is no any reason. My intention was I just installed Rust and hoped that developed programs will work out of the box.

I tried targets with another problem:

error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
 --> test.rs:1:1
  |
1 | extern crate windows_targets;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information

error: aborting due to 1 previous error

may I guess you didn't install visual C++ build tools? if you dont want to do that, the -windows-msvc toolchain will not work.

the -windows-gnu toolchain is self-contained, in that you don't need external tools for "pure rust" programs. (as soon as you want to use FFI libraries, you still need to install mingw gcc).

for a better OOB experience with the Windows API, you should use the windows or windows-sys crate. the windows-link crate is very low level, and it uses unstable (last time I checked) features of rust, so it's not really suitable for new learners.

did you add windows-targets to Cargo.toml as a dependency?

I do not use Cargo, just rustc. I think you right, I have to install some development tool beyond just Rust. Actually I switched to the gnu target, because Rust couldn't find link.exe. Thank you for the help.

for better OOB experience, I' suggest to stick with cargo (unless you are author of build tools who want to integrate rustc to your tool.)

cargo is not only a build tool, but also a package manager. it gives you smooth experience to use libraries from crates.io, which is the default registry of cargo, but you can use custom registries if needed.

with cargo, using third party crates is almost as easy as using the standard library. using your original example:

> cargo new hello
> cd hello
> cargo add windows-sys --features Win32_Foundation
> notepad src/main.rs
// main.rs
use windows_sys::Win32::Foundation::{GetLastError, SetLastError};
fn main() {
    unsafe {
        SetLastError(1234);
        assert_eq!(GetLastError(), 1234);
    }
}
> cargo run

there's a small inconvenience when it comes to the windows/windows-sys crates, namely, you must enable subsets of APIs explicitly using features, and there's a ton of them. but at least, microsoft provides a search interface:

because the Windows API set is so large, even the windows-sys crate, which contains only declarations of FFI types and function signatures, and linkage information, the compile time would be unmanageable if all the APIs are enabled unconditionally. bummer, but it is what it is. it's a trade off for the completeness of the full Windows API set.


using rustc directly is possible, but it won't be as easy, unless your code is very simple, e.g., only uses the standard library (i.e. std, alloc, core). anything beyond that is rather involved, e.g., you can pass the --verbose flag to see the the full command line of how rustc is invoked.

notably, direct access of OS APIs (bypasisng the standard library) needs to use third party crates, e.g. the libc crate, or even lower level, like nix for Posix systems, windows-sys for Windows.

I really surprised that Rust for Windows so complicated. Last time I used Turbo Pascal for Windows and somehow all mechanisms were hidden for me. My programs just worked. However if I use Rust I have to use Cargo and crates. It's a bit unusual, but it is the price for progress.

good old days.

FWIW, Cargo is the recommended way in all the documentation, and so ubiquitous that the vast majority of material assumes you're using it. Using plain rustc is what I'd consider unusual, like if you didn't use a build system for C#.

Cargo is just a tool to generate arguments for rustc.

Cargo also handles downloading and building dependencies.

That's like saying rustc is "just" a tool for generating arguments for the assembler: while technically kinda true, it misses a whole lot of complexity.

You are absolutely correct. However if you need to prepare a distribution package where your Rust exe is only a tiny piece, you may need other tools. Installation, configuration, upgrading, and so on is an another story. Even you need Python to build rustc itself. So, Cargo is an amazing tool, but for a very specialized task. I use a different tool with wide range of functionality and building Rust components is a small piece of the range.

A good advice , thank you.

Keep in mind that in the Windows 3 days Borland only had to port and maintain like a 1000 APIs, it's more like 100,000 now! It's better that the Windows API support is provided by Microsoft directly for pretty much everyone involved.

I would happy to work with the Windows 3 subset supported by Borland. The major problem is currently to call just one Windows API function. As only it will start working, I can get 100,000 set easily.