[Windows] Owned file dialogs stall for 20–30 seconds: synchronous cross-thread property reads during WinEvent handling
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 38/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Lĩnh vực
- backend-api-design, desktop
Hướng nghiên cứu
Start with src/platform/windows/window_windows.cpp:1074, src/window_property_dispatch.cpp:33–37, and the four marshalled getters identified in the issue; then trace OnWindowThread in src/platform/windows/window_docking_windows.h:54. Reproduce with an owned file dialog using lockParentWindow: true and compare with false. Done when owned dialogs appear promptly while retaining owner-relative modality and the cross-thread wait no longer stalls.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
Opening a native Save File dialog stalls for approximately 20 seconds after upgrading from window_manager 0.5.2 to 0.6.0, which introduces nativeapi / cnativeapi.
Thread dumps captured during the delay show the platform thread waiting inside cnativeapi while the dialog thread is inside NtUserSetFocus. Source inspection and disassembly identify synchronous cross-thread property reads with individual five-second timeouts.
Setting WindowsOptions(lockParentWindow: false) eliminates the delay in the tested application. Switching the same diagnostic binary back to true restores it.
Environment
- Windows 11, build 22621.4317, x64.
- Flutter 3.47.9, release AOT build.
window_manager: 0.6.0nativeapi/cnativeapi: 0.5.10file_picker: 13.3.2windows_file_picker: 2.0.1
Users originally reported the problem on Windows 10. The measurements and thread dumps below were collected on Windows 11; Windows 10 was not independently tested.
Reproduction
In an application using window_manager, open a save dialog through file_picker with lockParentWindow: true, cancel it, and repeat. Compare against false, including after restarting the process.
The relevant call pattern is:
await FilePicker.saveFile(
fileName: 'settings.json',
bytes: bytes,
windowsOptions: WindowsOptions(
lockParentWindow: true, // Compare with false.
),
);
This is a reduced illustration of the tested application’s call, not an independently verified standalone reproduction.
windows_file_picker opens the COM dialog from a separate Dart isolate. With true, it supplies an owner HWND to IFileDialog::Show; with false, it supplies no owner.
Expected: the dialog appears promptly while preserving its ownership and modal behavior.
Actual: the owned dialog takes tens of seconds to appear.
A/B results
| Configuration | Observation |
|---|---|
Previous application release using window_manager 0.5.2 |
Dialog visible within 0.50–0.59 s |
Current official release, lockParentWindow: true |
Absent at 19.17/19.18 s; visible at 20.61/20.49 s |
Diagnostic build, false, repeated invocation |
Absent at 0.232 s; visible at 0.358 s |
Same diagnostic build, false, first invocation after restart |
Absent at 0.233 s; visible at 0.359 s |
Same diagnostic build, switched back to true, repeated invocation without debugger |
Absent at 28.44 s; visible at 30.53 s |
The diagnostic build retained the official application’s executable and native DLLs, including cnativeapi.dll and flutter_windows.dll. Only the Dart AOT payload was rebuilt to override and log the option. The same AOT payload was used for both values.
These are observation bounds measured from the click, including automation overhead. A separate screenshot-only check also reproduced the delay, without UI Automation tree polling. All dialogs were cancelled.
Thread stacks during the delay
The original release was captured using CDB noninvasive attachment. Windows frames were resolved using Microsoft symbols.
Platform thread, abbreviated, current frame first:
ntdll!NtWaitForAlertByThreadId+0x14
ntdll!RtlSleepConditionVariableSRW+0x13b
KERNELBASE!SleepConditionVariableSRW+0x29
cnativeapi+0xc6fd8
cnativeapi+0xad45a
cnativeapi+0x28ab3
cnativeapi+0x28b95
cnativeapi+0xb0d7d
... cnativeapi WinEvent handling frames ...
user32!_ClientCallWinEventProc+0x46
ntdll!KiUserCallbackDispatcherContinue
win32u!NtUserGetMessage+0x14
user32!GetMessageW+0x2a
Dialog thread, abbreviated:
win32u!NtUserSetFocus+0x14
shell32!CSaveControlsModuleInner::_CreateControls+0x4d9
shell32!CSaveControlsModuleInner::SetSite+0x53
shell32!CSaveControlsModule::LayoutInitialized+0x49
... shell layout / ExplorerBrowser initialization ...
comdlg32!CFileOpenSave::_JumpToInitialLocation+0x1b7
comdlg32!CFileOpenSave::_InitOpenSaveDialog+0xc5f
comdlg32!CFileOpenSave::s_OpenSaveDlgProc+0x278
... user32 dialog creation ...
comdlg32!CFileOpenSave::Show+0xe92
With false, a control dump taken after the dialog appeared showed the platform thread normally waiting in:
win32u!NtUserGetMessage+0x14
user32!GetMessageW+0x2a
Identified blocking path
Inspection of the source shipped with cnativeapi 0.5.10, combined with disassembly, reconstructs this path:
WinEvent callback on the platform thread
-> WindowManager wraps the dialog HWND
-> Window::Window(void*)
-> WindowPropertyDispatch::Refresh
-> Read
-> cross-thread property getter
-> detail::OnWindowThread
-> PostToThread(dialog thread, ...)
-> condition_variable wait
Relevant source locations in that package:
src/platform/windows/window_windows.cpp:1074: theWindowconstructor callsWindowPropertyDispatch::Refresh.src/window_property_dispatch.cpp:33–37: readsIsMinimizable,IsMaximizable,IsClosable, andIsWindowControlButtonsVisible.src/platform/windows/window_windows.cpp:1827,1857,1898,1931: those getters marshal work to the HWND-owning thread.src/platform/windows/window_docking_windows.h:54:OnWindowThreadwaits up to five seconds for the posted task.
The platform thread therefore waits for work on the dialog thread while that thread is inside focus initialization for an owned window. This strongly indicates a circular dependency involving the owner/platform thread. The kernel-side dependency itself was not traced.
Four sequential five-second timeouts explain the usual approximately 20-second delay.
Additional stack samples, approximately five seconds apart, captured successive waits:
Return address in cnativeapi.dll |
Property read |
|---|---|
+0x28ab3 |
IsMaximizable |
+0x28ac9 |
IsClosable |
+0x28ad4 |
IsWindowControlButtonsVisible |
These internal C++ names were reconstructed from source and disassembly, not resolved from a private PDB. The additional delay in the 30-second run was not individually traced.
Workaround and requested fix
lockParentWindow: false avoids the stall, but removes owner-relative modality, so it changes application behavior.
Could the WinEvent/window-registration path avoid synchronously waiting for another window-owning thread while refreshing properties? The desired behavior is to keep owned file dialogs responsive without requiring applications to disable modality.
- Ngôn ngữ chính
- TypeScript
- Star
- 172
- Fork
- 16
- Merge trung bình
- 40 phút
- Pull request đã merge (30 ngày)
- 2
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của libnativeapi/nativeapi
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
libnativeapi/nativeapi#32 ·
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 56/100
libnativeapi/nativeapi#31 · 1 bình luận · 2 reaction ·
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 38/100
libnativeapi/nativeapi#30 ·
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 56/100
libnativeapi/nativeapi#28 · 3 bình luận ·
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
libnativeapi/nativeapi#27 ·
Tất cả issue của libnativeapi/nativeapi
Issue tương tự
-
Mend: dependency security vulnerability
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 65/100
fdm-monster/fdm-monster#5563 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
be-BOP-io-SA/be-BOP#2849 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 79/100
Maintainer thường phản hồi trong vòng 1 ngày
-
1️⃣ phase/under-investigation flaky/confirmed flaky/needs-decision type/bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
growilabs/growi#12246 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
🐛 The Rulekeeper - An index run that gives up on the lock ends SucceededCó thể đã có người làm @github-actions đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
SSWConsulting/SSW.Rules#2809 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày