tauri
tauri copied to clipboard
[bug] `STATUS_ENTRYPOINT_NOT_FOUND` error when running command `cargo test` on Windows
Describe the bug
If you use the mock function in tauri::test on Windows, you won't be able to run the test.
- on
src-tauridirectory.
$ cargo test -- --nocapture
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.98s
Running unittests src\lib.rs (target\debug\deps\optain_lib-68a81ae245c485fa.exe)
error: test failed, to rerun pass `--lib`
Caused by:
process didn't exit successfully: `C:\Users\PC\sources\Tauri\optain\app\src-tauri\target\debug\deps\optain_lib-68a81ae245c485fa.exe --nocapture` (exit code: 0xc0000139, STATUS_ENTRYPOINT_NOT_FOUND)
Reproduction
The test code that causes this error is shown below: This code does not work on Windows, but works fine on macOS.
use super::*;
use tauri::{
test::{mock_builder, mock_context, noop_assets, MockRuntime},
App, Manager,
};
fn create_mock_app(enable_by_language: bool) -> App<MockRuntime> {
mock_builder()
.plugin(tauri_plugin_store::Builder::new().build())
.manage(SurveyState::new(enable_by_language))
.build(mock_context(noop_assets()))
.unwrap()
}
#[test]
fn not_executed_10times() {
let app = create_mock_app(true);
let app_handle = app.handle();
let survey_state = app.state::<SurveyState>();
let result = survey_state.init(&app_handle);
assert!(result.is_ok());
for _ in 0..9 {
// 9 times
survey_state.increase_executed_count().unwrap();
}
assert_eq!(survey_state.count_executed.lock().unwrap().to_owned(), 9);
// if not executed 10 times, survey must not be opened
assert!(!survey_state.default_condition().unwrap());
let next_day = DAY_IN_SECS + 1;
assert!(!survey_state.will_open_on_setting_window(next_day).unwrap());
assert!(!survey_state.will_open_on_popup(next_day * 3).unwrap());
}
Expected behavior
No response
Full tauri info output
[✔] Environment
- OS: Windows 10.0.19045 x86_64 (X64)
✔ WebView2: 136.0.3240.64
✔ MSVC: Visual Studio Community 2022
✔ rustc: 1.86.0 (05f9846f8 2025-03-31)
✔ cargo: 1.86.0 (adf9b6ad1 2025-02-28)
✔ rustup: 1.28.2 (e4f3ad6f8 2025-04-28)
✔ Rust toolchain: stable-x86_64-pc-windows-msvc (default)
- node: 20.19.0
- pnpm: 9.15.9
- npm: 10.8.2
[-] Packages
- tauri 🦀: 2.5.1
- tauri-build 🦀: 2.2.0
- wry 🦀: 0.51.2
- tao 🦀: 0.33.0
- @tauri-apps/api : not installed!
- @tauri-apps/cli : 2.4.1 (outdated, latest: 2.5.0)
[-] Plugins
- tauri-plugin-log 🦀: 2.4.0
- @tauri-apps/plugin-log : not installed!
- tauri-plugin-autostart 🦀: 2.3.0
- @tauri-apps/plugin-autostart : not installed!
- tauri-plugin-opener 🦀: 2.2.6
- @tauri-apps/plugin-opener : not installed!
- tauri-plugin-dialog 🦀: 2.2.1
- @tauri-apps/plugin-dialog : not installed!
- tauri-plugin-positioner 🦀: 2.2.0
- @tauri-apps/plugin-positioner : not installed!
- tauri-plugin-window-state 🦀: 2.2.2
- @tauri-apps/plugin-window-state : not installed!
- tauri-plugin-clipboard-manager 🦀: 2.2.2
- @tauri-apps/plugin-clipboard-manager : not installed!
- tauri-plugin-updater 🦀: 2.7.1
- @tauri-apps/plugin-updater : not installed!
- tauri-plugin-fs 🦀: 2.2.1
- @tauri-apps/plugin-fs : not installed!
- tauri-plugin-store 🦀: 2.2.0
- @tauri-apps/plugin-store : not installed!
- tauri-plugin-single-instance 🦀: 2.2.3
- @tauri-apps/plugin-single-instance : not installed!
[-] App
- build-type: bundle
- CSP: unset
- frontendDist: ../dist
- devUrl: http://localhost:1420/
- framework: React
- bundler: Vite
Stack trace
Additional context
My project consists of wrapping a Tauri app in a monorepo of Turbo.
try adding a file like this https://github.com/tauri-apps/tauri/blob/dev/.cargo/config.toml
try adding a file like this https://github.com/tauri-apps/tauri/blob/dev/.cargo/config.toml
@FabianLars I've been looking into this and noticed a few things. From my understanding, this happens because during tests, the binary doesn't contain the manifest it should have, and thus, the entry point isn't found.
-
tauri-buildusescompile()fromtauri-winresto compile and link the manifest to the binary: https://github.com/tauri-apps/tauri/blob/06c75fd98b84da21112bc2eb93c238224af3e06b/crates/tauri-build/src/lib.rs#L657-L662 -
tauri-winresthen callscompile()fromembed-resources: -
embed-resourcesthen links the manifest usingrustc-link-arg-bins(notice the-bins):
This only links the manifest to the main application binary, not any of the tests. (see https://github.com/nabijaczleweli/rust-embed-resource/issues/69)
If tauri-winres used compile_for_everything instead, it would also link the manifest to the tests, just like the workaround does.
Likewise, but link the resource into every artifact: binaries, cdylibs, examples, tests (
[[test]]/#[test]/doctest), benchmarks, &c.
Changing this one call from compile to compile_for_everything inside of tauri-winres should fix this issue entirely.
Note: I didn't want to open another issue for this, since that would make this the third STATUS_ENTRYPOINT_NOT_FOUND related issue in the past 2 weeks 😅
i won't change the current call for everyone but check if we can make it an option in a reasonable way, thx for digging that up
i got same issue.
i already set
[env]
__TAURI_WORKSPACE__ = "true"
but isn't working.
i still got (exit code: 0xc0000139, STATUS_ENTRYPOINT_NOT_FOUND)
win10 OS.
please,help me,thank you so much;
@FabianLars
what I've done in the past to workaround this is to embed the app manifest manually:
build.rs:
fn main() {
let mut attributes = tauri_build::Attributes::new();
#[cfg(windows)]
{
attributes = attributes.windows_attributes(tauri_build::WindowsAttributes::new_without_app_manifest());
add_manifest();
}
tauri_build::try_build(attributes).unwrap();
}
#[cfg(windows)]
fn add_manifest() {
static WINDOWS_MANIFEST_FILE: &str = "windows-app-manifest.xml";
let manifest = std::env::current_dir()
.unwrap()
.join(WINDOWS_MANIFEST_FILE);
println!("cargo:rerun-if-changed={}", manifest.display());
// Embed the Windows application manifest file.
println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
println!(
"cargo:rustc-link-arg=/MANIFESTINPUT:{}",
manifest.to_str().unwrap()
);
// Turn linker warnings into errors.
println!("cargo:rustc-link-arg=/WX");
}
windows-app-manifest.xml (next to build.rs):
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
This only links the manifest to the main application binary, not any of the tests
that's what i assumed too.. thanks for investigating it all the way
If this won't be fixed by the fix for #13419 (not done yet) then i think you won't get around disabling tauri's the v6-common-controls feature flag or giving the importer's app a build script to apply the manifest as well🤔
just a sidenote
having to work on a legacy app (old Delphi) that can not use themes, there is some crazy windows embedding there, that just become broken when you enable themes
In the end i did the same. Except i did not put an external XML file, you can not have a manifest from memory (from a variable) but it perfectly works from the EXE/DLL resources, you just have to give it an explicit text-name, as the integer-named resources are reserved by Microsoft for special purposes.
But note... Initially we did it not even using anything about manifests. On real Windows your desktop app always has ComCtl6 even without any manifest and you can use it.
However, there were unexpected traps.
- Windows XP royally mixed concerns, when they made the same manifest BOTH enable themes and choose ComCtl version
- As implemented in Windows 7 to 11, the ComCtl 5 is the stub loading ComCtl 6 and removing some entries, so they would feign the
STATUS_ENTRYPOINT_NOT_FOUNDfor you. It is there, loaded, but will not be returned. - However mere enumerating the loaded modules reveals the true ComCtl and you can get any function from that. We used it to run the TaskDialogIndirect which was zeroed-out in the ComCtl5 fake.
So we just took the real ComCtl32, incremented its refcounter and used API from it when we needed, while keeping our app manifest-free.
Now is where things are getting interesting...
- WinE library announced they are discarding the same "stub" approach and instead would fork ComCtl into v5 and v6 different subprojects and would independently mantain and supply both.
Should mean the "just find it" approach would not work there. If you would ever care about running on WinE/Odin/etc of course.
- Worse: we met a specific Win11 box where this "already there, just find and use" approach insta-crashed the program the moment toy called the TaskDialog API. Weird thing, WerFault was triggered TWICE when the app was crashing and EventVwr showed two records for every crash.
There was nothing suspicious written between the normal call and the crash. No other box behaved like that for months and months. No meaningful difference from other Win11 boxes was detected. Also, usual applications like the desktop again were not insta-crashing when using ComCtl6
Maybe - just speculating out of despair - it had OBStudio running.
There was never a single other box doing so, but the user suypprot nightmare made as look how to avoid it.
Had to google around the almost undocumented "context activation" API (and ended the same place you are in).
Interesting detail: the official manifest docs have the "disable themes" command, theoretically giving you a method to have a theme-less ComCtl6. But it does not work in any official Windows version. It probably was implemented in LongHorn then removed. Anyway, asking about that flag on Microsoft Ask gets you banned. So, just consider it non-existing and documentation error.
The good thing: TaskDialog is modal API, meaning it would not return control until finished, and we could not care about any modified global state leaking out. We could alter the state then call the API then pop out the change.
And we deed, indeed. Creating and activating the temporary "ComCtl6" activation context, then calling the ComCtl6 modal API, then deleting it fixed the ComCtl6 crash. Actually, we did it twice. Early-on to test perma-load ComCtl6 and fix the handle, then to test if ComCtl6 MUI (i18l) can be loaded for a moment. Then eveyr time we call the ComCtl6-specific API. But one had to avoid tantalizingly named but undocumented "set as process default" flag when activating.