@@ -78,7 +78,15 @@ void GetDebugPrivilege() {
7878 CloseHandle (hToken);
7979}
8080
81+ void ShowCrashDialog ();
82+
83+ constexpr int MAX_CRASH_COUNT = 3 ;
8184int InjectToPID (int targetPID, std::wstring_view dllPath) {
85+ static int crash_count = 0 ;
86+
87+ if (crash_count >= MAX_CRASH_COUNT) {
88+ return 1 ;
89+ }
8290
8391 HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE , targetPID);
8492 if (hProcess == NULL ) {
@@ -118,8 +126,23 @@ int InjectToPID(int targetPID, std::wstring_view dllPath) {
118126
119127 WaitForSingleObject (hThread, INFINITE);
120128 CloseHandle (hThread);
121- VirtualFreeEx (hProcess, remoteString, 0 , MEM_RELEASE);
122- CloseHandle (hProcess);
129+
130+ std::thread ([hProcess]() {
131+ WaitForSingleObject (hProcess, INFINITE);
132+ auto exitCode = 0 ;
133+ if (!GetExitCodeProcess (hProcess, (LPDWORD)&exitCode)) {
134+ std::cerr << " GetExitCodeProcess failed: " << GetLastError () << std::endl;
135+ }
136+ if (exitCode != 0 ) {
137+ std::cerr << " Process exited with code: " << exitCode << std::endl;
138+ if (++crash_count >= MAX_CRASH_COUNT) {
139+ ShowCrashDialog ();
140+ }
141+ } else {
142+ crash_count = 0 ; // Reset crash count on successful injection
143+ }
144+ CloseHandle (hProcess);
145+ }).detach ();
123146
124147 std::cout << " DLL injected successfully." << std::endl;
125148 return 0 ;
@@ -386,6 +409,7 @@ void InjectAllConsistent() {
386409
387410struct inject_all_switch : public button_widget {
388411 bool injecting_all = false ;
412+ std::chrono::steady_clock::time_point last_check;
389413 inject_all_switch () : button_widget(english ? " Inject All" : " 全局注入" ) {
390414 check_is_injecting_all ();
391415 }
@@ -420,11 +444,6 @@ struct inject_all_switch : public button_widget {
420444 }
421445
422446 restart_explorer ();
423-
424- std::thread ([this ]() {
425- Sleep (200 );
426- check_is_injecting_all ();
427- }).detach ();
428447 }
429448
430449 void update_colors (bool is_active, bool is_hovered) override {
@@ -437,6 +456,12 @@ struct inject_all_switch : public button_widget {
437456 } else {
438457 button_widget::update_colors (is_active, is_hovered);
439458 }
459+
460+ if (std::chrono::steady_clock::now () - last_check >
461+ std::chrono::seconds (1 )) {
462+ check_is_injecting_all ();
463+ last_check = std::chrono::steady_clock::now ();
464+ }
440465 }
441466};
442467
@@ -546,10 +571,111 @@ void StartInjectUI() {
546571 return ;
547572 }
548573 nvgCreateFont (rt.nvg , " main" , " C:\\ WINDOWS\\ FONTS\\ msyh.ttc" );
549-
550574 rt.root ->emplace_child <injector_ui_main>();
575+ rt.start_loop ();
576+ }
577+
578+ void ShowCrashDialog () {
579+ auto show_by_messagebox = []() {
580+ MessageBoxW (
581+ NULL ,
582+ english
583+ ? L" Explorer has crashed too many times after injection.\n Breeze "
584+ L" Shell will now exit to prevent further crashes."
585+ : L" 注入后资源管理器多次崩溃。\n Breeze Shell "
586+ L" 将退出以防止进一步崩溃。" ,
587+ english ? L" Breeze Shell Error" : L" Breeze Shell 错误" ,
588+ MB_ICONERROR | MB_OK);
589+ };
590+ if (auto r = ui::render_target::init_global (); !r) {
591+ std::cerr << " Failed to initialize global render target." << std::endl;
592+ show_by_messagebox ();
593+ return ;
594+ }
595+
596+ ui::render_target rt;
597+ rt.acrylic = 0.1 ;
598+ rt.transparent = true ;
599+ rt.width = 400 ;
600+ rt.height = 230 ;
601+ rt.title = " " ;
602+
603+ if (auto r = rt.init (); !r) {
604+ std::cerr << " Failed to initialize render target." << std::endl;
605+ show_by_messagebox ();
606+ return ;
607+ }
608+
609+ nvgCreateFont (rt.nvg , " main" , " C:\\ WINDOWS\\ FONTS\\ msyh.ttc" );
610+
611+ // Create error UI
612+ auto error_ui = rt.root ->emplace_child <ui::widget_flex>();
613+ error_ui->gap = 15 ;
614+ error_ui->x ->reset_to (20 );
615+ error_ui->y ->reset_to (0 );
616+
617+ // Icon
618+ error_ui->emplace_child <breeze_icon>();
619+
620+ // Error message
621+ auto msg_box = error_ui->emplace_child <ui::widget_flex>();
622+ msg_box->gap = 10 ;
623+
624+ auto title = msg_box->emplace_child <ui::text_widget>();
625+ title->text = " Breeze Shell Error" ;
626+ title->font_size = 20 ;
627+ title->color .reset_to ({1 , 0.4 , 0.4 , 1 });
628+
629+ auto message = msg_box->emplace_child <ui::text_widget>();
630+ message->text = english
631+ ? " Explorer has crashed multiple times after injection."
632+ : " 资源管理器在注入后多次崩溃,这可能是 Breeze 的问题。" ;
633+ message->font_size = 14 ;
634+ message->color .reset_to ({1 , 1 , 1 , 0.9 });
635+
636+ auto suggestion = msg_box->emplace_child <ui::text_widget>();
637+ suggestion->text = english ? " Breeze Shell will be temporarily disabled to "
638+ " prevent further crashes."
639+ : " Breeze 将暂时被禁用,以防止持续崩溃。" ;
640+ suggestion->font_size = 14 ;
641+ suggestion->color .reset_to ({1 , 1 , 1 , 0.9 });
642+
643+ auto suggestion2 = msg_box->emplace_child <ui::text_widget>();
644+ suggestion2->text = english
645+ ? " If you want to continue using Breeze Shell, "
646+ " please re-enable it in the injector UI."
647+ : " 如果您想继续使用 Breeze,请在注入器中重新启用。" ;
648+ suggestion2->font_size = 14 ;
649+ suggestion2->color .reset_to ({1 , 1 , 1 , 0.9 });
650+
651+ auto btn_container = error_ui->emplace_child <ui::widget_flex>();
652+ btn_container->horizontal = true ;
653+ btn_container->gap = 10 ;
654+
655+ class close_button : public button_widget {
656+ public:
657+ close_button () : button_widget(english ? " Close" : " 关闭" ) {}
658+ void on_click () override { exit (1 ); }
659+ };
660+
661+ class github_button : public button_widget {
662+ public:
663+ github_button () : button_widget(english ? " Check GitHub" : " 查看 GitHub" ) {}
664+ void on_click () override {
665+ ShellExecuteW (
666+ NULL , L" open" ,
667+ L" https://github.com/std-microblock/breeze-shell/releases/latest" ,
668+ NULL , NULL , SW_SHOW);
669+ }
670+ };
551671
672+ btn_container->emplace_child <close_button>();
673+ btn_container->emplace_child <github_button>();
552674 rt.start_loop ();
675+ HANDLE event =
676+ CreateEventW (NULL , TRUE , FALSE , L" breeze-shell-inject-consistent-exit" );
677+ SetEvent (event);
678+ CloseHandle (event);
553679}
554680
555681void UpdateDllPath () {
0 commit comments