From da59de8b3a1c067ecf0131d30c66a2896ff4cf9e Mon Sep 17 00:00:00 2001 From: boyan01 <17426470+boyan01@users.noreply.github.com> Date: Sun, 28 Dec 2025 22:03:01 +0800 Subject: [PATCH 1/4] feat: fix crash on multi engine --- .gitignore | 2 +- .../example/lib/main.dart | 12 ++ .../window_proc_delegate/example/pubspec.lock | 10 +- .../window_proc_delegate/example/pubspec.yaml | 55 +------ .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + .../example/windows/runner/flutter_window.cpp | 11 +- .../src/window_proc_delegate_internal.dart | 6 +- .../window_proc_delegate_plugin_c_api.h | 33 ---- .../windows/window_proc_delegate_plugin.cpp | 144 +++++++++++++++--- .../windows/window_proc_delegate_plugin.h | 43 +++++- .../window_proc_delegate_plugin_c_api.cpp | 100 ------------ 12 files changed, 206 insertions(+), 214 deletions(-) diff --git a/.gitignore b/.gitignore index fb66d2f..402ec5e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,5 @@ migrate_working_dir/ *.ipr *.iws .idea/ - +.vscode diff --git a/packages/window_proc_delegate/example/lib/main.dart b/packages/window_proc_delegate/example/lib/main.dart index 66c4e0c..9b3afd3 100644 --- a/packages/window_proc_delegate/example/lib/main.dart +++ b/packages/window_proc_delegate/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:window_proc_delegate/window_proc_delegate.dart'; +import 'package:desktop_multi_window/desktop_multi_window.dart'; void main() { runApp(const MyApp()); @@ -84,6 +85,12 @@ class _MyAppState extends State { } } + void _createChildWindow() async { + await WindowController.create( + WindowConfiguration(hiddenAtLaunch: false, arguments: ''), + ); + } + @override Widget build(BuildContext context) { return MaterialApp( @@ -106,6 +113,11 @@ class _MyAppState extends State { onPressed: _delegateId != null ? _unregisterDelegate : null, child: const Text('Unregister Delegate'), ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: _createChildWindow, + child: const Text('Create Child Window'), + ), ], ), const SizedBox(height: 8), diff --git a/packages/window_proc_delegate/example/pubspec.lock b/packages/window_proc_delegate/example/pubspec.lock index 0cb0d72..de5e796 100644 --- a/packages/window_proc_delegate/example/pubspec.lock +++ b/packages/window_proc_delegate/example/pubspec.lock @@ -49,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + desktop_multi_window: + dependency: "direct main" + description: + name: desktop_multi_window + sha256: "60ba38725b8887b60e44d15afdcf0c3813568b5da2ccaf1e7f6fd09a380a6e24" + url: "https://pub.dev" + source: hosted + version: "0.3.0" fake_async: dependency: transitive description: @@ -269,7 +277,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1" + version: "0.0.2" sdks: dart: ">=3.10.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/window_proc_delegate/example/pubspec.yaml b/packages/window_proc_delegate/example/pubspec.yaml index 7a5ad2d..533332b 100644 --- a/packages/window_proc_delegate/example/pubspec.yaml +++ b/packages/window_proc_delegate/example/pubspec.yaml @@ -18,68 +18,15 @@ dependencies: sdk: flutter window_proc_delegate: - # When depending on this package from a real application you should use: - # window_proc_delegate: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. path: ../ - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 + desktop_multi_window: ^0.3.0 dev_dependencies: integration_test: sdk: flutter flutter_test: sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. flutter_lints: ^6.0.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/packages/window_proc_delegate/example/windows/flutter/generated_plugin_registrant.cc b/packages/window_proc_delegate/example/windows/flutter/generated_plugin_registrant.cc index 615114a..b7f701a 100644 --- a/packages/window_proc_delegate/example/windows/flutter/generated_plugin_registrant.cc +++ b/packages/window_proc_delegate/example/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,12 @@ #include "generated_plugin_registrant.h" +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + DesktopMultiWindowPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DesktopMultiWindowPlugin")); WindowProcDelegatePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowProcDelegatePluginCApi")); } diff --git a/packages/window_proc_delegate/example/windows/flutter/generated_plugins.cmake b/packages/window_proc_delegate/example/windows/flutter/generated_plugins.cmake index bed7962..7144ba0 100644 --- a/packages/window_proc_delegate/example/windows/flutter/generated_plugins.cmake +++ b/packages/window_proc_delegate/example/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + desktop_multi_window window_proc_delegate ) diff --git a/packages/window_proc_delegate/example/windows/runner/flutter_window.cpp b/packages/window_proc_delegate/example/windows/runner/flutter_window.cpp index 955ee30..6ebf9d6 100644 --- a/packages/window_proc_delegate/example/windows/runner/flutter_window.cpp +++ b/packages/window_proc_delegate/example/windows/runner/flutter_window.cpp @@ -2,6 +2,7 @@ #include +#include "desktop_multi_window/desktop_multi_window_plugin.h" #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) @@ -25,11 +26,15 @@ bool FlutterWindow::OnCreate() { return false; } RegisterPlugins(flutter_controller_->engine()); + DesktopMultiWindowSetWindowCreatedCallback([](void* controller) { + auto* flutter_view_controller = + reinterpret_cast(controller); + auto* registry = flutter_view_controller->engine(); + RegisterPlugins(registry); + }); SetChildContent(flutter_controller_->view()->GetNativeWindow()); - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); + flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); // Flutter can complete the first frame before the "show window" callback is // registered. The following call ensures a frame is pending to ensure the diff --git a/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart b/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart index 6e74745..432a57f 100644 --- a/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart +++ b/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart @@ -1,5 +1,6 @@ import 'dart:ffi' as ffi; import 'dart:io'; +import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; import 'windows_message.dart'; import '../window_proc_delegate.dart'; @@ -69,8 +70,11 @@ void initialize( // Get the engine ID and register the native callback try { - final engineId = PlatformDispatcher.instance.engineId!; + final int engineId = PlatformDispatcher.instance.engineId!; setCallback(engineId, nativeCallable.nativeFunction); + + final channel = MethodChannel('window_proc_delegate'); + channel.invokeMethod('setEngineId', engineId); } catch (e) { debugPrint('Failed to set callback: $e'); } diff --git a/packages/window_proc_delegate/windows/include/window_proc_delegate/window_proc_delegate_plugin_c_api.h b/packages/window_proc_delegate/windows/include/window_proc_delegate/window_proc_delegate_plugin_c_api.h index c41dd55..3ca4652 100644 --- a/packages/window_proc_delegate/windows/include/window_proc_delegate/window_proc_delegate_plugin_c_api.h +++ b/packages/window_proc_delegate/windows/include/window_proc_delegate/window_proc_delegate_plugin_c_api.h @@ -2,8 +2,6 @@ #define FLUTTER_PLUGIN_WINDOW_PROC_DELEGATE_PLUGIN_C_API_H_ #include -#include -#include #ifdef FLUTTER_PLUGIN_IMPL #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) @@ -11,46 +9,15 @@ #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) #endif -// Forward declaration -namespace window_proc_delegate { -struct WindowsMessage; -} - #if defined(__cplusplus) extern "C" { #endif -// Callback signature for Dart WindowProc delegate -typedef void (*DartWindowProcCallbackC)( - window_proc_delegate::WindowsMessage* message); - FLUTTER_PLUGIN_EXPORT void WindowProcDelegatePluginCApiRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar); -FLUTTER_PLUGIN_EXPORT void WindowProcDelegateSetCallback( - int64_t engineId, DartWindowProcCallbackC callback); - -FLUTTER_PLUGIN_EXPORT intptr_t WindowProcDelegateInitDartApi(void* data); - #if defined(__cplusplus) } // extern "C" #endif -// C++ only functions (not in extern "C") -#if defined(__cplusplus) -#include - -namespace window_proc_delegate { -typedef std::function DartWindowProcCallback; -} - -// Get the callback for a specific engine ID -window_proc_delegate::DartWindowProcCallback GetCallbackForEngine( - int64_t engineId); - -// Get all registered callbacks -std::vector GetAllCallbacks(); - -#endif - #endif // FLUTTER_PLUGIN_WINDOW_PROC_DELEGATE_PLUGIN_C_API_H_ diff --git a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp index 307cdfe..73be1cf 100644 --- a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp +++ b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp @@ -1,13 +1,14 @@ #include "window_proc_delegate_plugin.h" +#include "dart/dart_api_dl.h" #include "include/window_proc_delegate/window_proc_delegate_plugin_c_api.h" - // This must be included before many other Windows headers. #include #include #include #include +#include #include #include #include @@ -38,23 +39,20 @@ WindowProcDelegatePlugin::WindowProcDelegatePlugin( window_proc_delegate_id_ = registrar->RegisterTopLevelWindowProcDelegate( [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -> std::optional { - // Get all registered callbacks and invoke them - auto callbacks = GetAllCallbacks(); - for (const auto& callback : callbacks) { - if (callback) { - WindowsMessage msg = {}; - msg.windowHandle = reinterpret_cast(hwnd); - msg.message = static_cast(message); - msg.wParam = static_cast(wparam); - msg.lParam = static_cast(lparam); - msg.lResult = 0; - msg.handled = false; - - callback(&msg); - - if (msg.handled) { - return static_cast(msg.lResult); - } + auto callback = GetCallback(); + if (callback) { + WindowsMessage msg = {}; + msg.windowHandle = reinterpret_cast(hwnd); + msg.message = static_cast(message); + msg.wParam = static_cast(wparam); + msg.lParam = static_cast(lparam); + msg.lResult = 0; + msg.handled = false; + + callback(&msg); + + if (msg.handled) { + return static_cast(msg.lResult); } } return std::nullopt; @@ -62,13 +60,121 @@ WindowProcDelegatePlugin::WindowProcDelegatePlugin( } WindowProcDelegatePlugin::~WindowProcDelegatePlugin() { + if (engine_id_ != -1) { + UnregisterPlugin(engine_id_); + } registrar_->UnregisterTopLevelWindowProcDelegate(window_proc_delegate_id_); } void WindowProcDelegatePlugin::HandleMethodCall( const flutter::MethodCall& method_call, std::unique_ptr> result) { - result->NotImplemented(); + if (method_call.method_name().compare("setEngineId") == 0) { + const auto* arguments = method_call.arguments(); + if (const auto* engine_id = std::get_if(arguments)) { + engine_id_ = *engine_id; + RegisterPlugin(engine_id_, this); + result->Success(); + } else { + result->Error("INVALID_ARGUMENT", "Engine ID must be an integer"); + } + } else { + result->NotImplemented(); + } +} + +void WindowProcDelegatePlugin::SetCallback(DartWindowProcCallbackC callback, + Dart_Isolate isolate) { + std::lock_guard lock(mutex_); + callback_ = callback; + isolate_ = isolate; +} + +DartWindowProcCallback WindowProcDelegatePlugin::GetCallback() { + std::lock_guard lock(mutex_); + if (!callback_ || !isolate_) { + return nullptr; + } + + return [callback = callback_, isolate = isolate_](WindowsMessage* message) { + // Enter the Dart isolate before calling the callback + Dart_Isolate previous = Dart_CurrentIsolate_DL(); + if (previous != isolate) { + if (previous) { + Dart_ExitIsolate_DL(); + } + Dart_EnterIsolate_DL(isolate); + } + + callback(message); + + // Restore previous isolate + Dart_Isolate current = Dart_CurrentIsolate_DL(); + if (previous != isolate) { + if (current) { + Dart_ExitIsolate_DL(); + } + if (previous) { + Dart_EnterIsolate_DL(previous); + } + } + }; +} + +// Global state for plugin registration +namespace { +std::map g_plugins; +std::map> + g_pending_callbacks; +std::mutex g_mutex; +} // namespace + +// static +void WindowProcDelegatePlugin::RegisterPlugin( + int64_t engine_id, WindowProcDelegatePlugin* plugin) { + std::lock_guard lock(g_mutex); + g_plugins[engine_id] = plugin; + + // Check for pending callbacks + auto it = g_pending_callbacks.find(engine_id); + if (it != g_pending_callbacks.end()) { + plugin->SetCallback(it->second.first, it->second.second); + g_pending_callbacks.erase(it); + } +} + +// static +void WindowProcDelegatePlugin::UnregisterPlugin(int64_t engine_id) { + std::lock_guard lock(g_mutex); + g_plugins.erase(engine_id); + g_pending_callbacks.erase(engine_id); +} + +// static +void WindowProcDelegatePlugin::SetCallbackForEngine( + int64_t engine_id, DartWindowProcCallbackC callback, Dart_Isolate isolate) { + std::lock_guard lock(g_mutex); + if (g_plugins.find(engine_id) != g_plugins.end()) { + // Plugin already registered, set callback directly + g_plugins[engine_id]->SetCallback(callback, isolate); + } else { + // Plugin not yet registered, store as pending + if (callback) { + g_pending_callbacks[engine_id] = std::make_pair(callback, isolate); + } else { + g_pending_callbacks.erase(engine_id); + } + } } } // namespace window_proc_delegate + +void WindowProcDelegateSetCallback(int64_t engineId, + DartWindowProcCallbackC callback) { + window_proc_delegate::WindowProcDelegatePlugin::SetCallbackForEngine( + engineId, callback, Dart_CurrentIsolate_DL()); +} + +intptr_t WindowProcDelegateInitDartApi(void* data) { + return Dart_InitializeApiDL(data); +} diff --git a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h index 3c68b7c..e295dbe 100644 --- a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h +++ b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h @@ -1,15 +1,17 @@ #ifndef FLUTTER_PLUGIN_WINDOW_PROC_DELEGATE_PLUGIN_H_ #define FLUTTER_PLUGIN_WINDOW_PROC_DELEGATE_PLUGIN_H_ - #include #include #include +#include #include +#include "dart/dart_api_dl.h" +#include "include/window_proc_delegate/window_proc_delegate_plugin_c_api.h" + namespace window_proc_delegate { -// Windows message structure struct WindowsMessage { intptr_t windowHandle; int32_t message; @@ -19,6 +21,28 @@ struct WindowsMessage { bool handled; }; +} // namespace window_proc_delegate + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef void (*DartWindowProcCallbackC)( + window_proc_delegate::WindowsMessage* message); + +FLUTTER_PLUGIN_EXPORT void WindowProcDelegateSetCallback( + int64_t engineId, DartWindowProcCallbackC callback); + +FLUTTER_PLUGIN_EXPORT intptr_t WindowProcDelegateInitDartApi(void* data); + +#if defined(__cplusplus) +} // extern "C" +#endif + +namespace window_proc_delegate { + +typedef std::function DartWindowProcCallback; + class WindowProcDelegatePlugin : public flutter::Plugin { public: static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); @@ -36,9 +60,24 @@ class WindowProcDelegatePlugin : public flutter::Plugin { const flutter::MethodCall& method_call, std::unique_ptr> result); + void SetCallback(DartWindowProcCallbackC callback, Dart_Isolate isolate); + DartWindowProcCallback GetCallback(); + + // Static methods for global registration + static void RegisterPlugin(int64_t engine_id, + WindowProcDelegatePlugin* plugin); + static void UnregisterPlugin(int64_t engine_id); + static void SetCallbackForEngine(int64_t engine_id, + DartWindowProcCallbackC callback, + Dart_Isolate isolate); + private: flutter::PluginRegistrarWindows* registrar_; int window_proc_delegate_id_; + int64_t engine_id_ = -1; + DartWindowProcCallbackC callback_ = nullptr; + Dart_Isolate isolate_ = nullptr; + std::mutex mutex_; }; } // namespace window_proc_delegate diff --git a/packages/window_proc_delegate/windows/window_proc_delegate_plugin_c_api.cpp b/packages/window_proc_delegate/windows/window_proc_delegate_plugin_c_api.cpp index 53fa32c..0c1e255 100644 --- a/packages/window_proc_delegate/windows/window_proc_delegate_plugin_c_api.cpp +++ b/packages/window_proc_delegate/windows/window_proc_delegate_plugin_c_api.cpp @@ -2,111 +2,11 @@ #include -#include -#include -#include - -#include "dart_api_dl.h" #include "window_proc_delegate_plugin.h" -namespace { -// Global map to store callbacks and isolates for each engine -std::map> g_callbacks; -} // namespace - void WindowProcDelegatePluginCApiRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar) { window_proc_delegate::WindowProcDelegatePlugin::RegisterWithRegistrar( flutter::PluginRegistrarManager::GetInstance() ->GetRegistrar(registrar)); } - -void WindowProcDelegateSetCallback(int64_t engineId, - DartWindowProcCallbackC callback) { - if (callback) { - // Store the callback and current isolate - Dart_Isolate current_isolate = Dart_CurrentIsolate_DL(); - g_callbacks[engineId] = std::make_pair(callback, current_isolate); - } else { - // Remove the callback for this engine - g_callbacks.erase(engineId); - } -} - -window_proc_delegate::DartWindowProcCallback GetCallbackForEngine( - int64_t engineId) { - auto it = g_callbacks.find(engineId); - if (it == g_callbacks.end()) { - return nullptr; - } - - auto callback = it->second.first; - auto isolate = it->second.second; - - // Return a lambda that handles isolate management - return [callback, isolate](window_proc_delegate::WindowsMessage* message) { - if (callback && isolate) { - // Enter the Dart isolate before calling the callback - Dart_Isolate previous = Dart_CurrentIsolate_DL(); - if (previous != isolate) { - if (previous) { - Dart_ExitIsolate_DL(); - } - Dart_EnterIsolate_DL(isolate); - } - - callback(message); - - // Restore previous isolate - Dart_Isolate current = Dart_CurrentIsolate_DL(); - if (previous != isolate) { - if (current) { - Dart_ExitIsolate_DL(); - } - if (previous) { - Dart_EnterIsolate_DL(previous); - } - } - } - }; -} - -std::vector GetAllCallbacks() { - std::vector callbacks; - for (const auto& entry : g_callbacks) { - auto callback = entry.second.first; - auto isolate = entry.second.second; - - if (callback && isolate) { - callbacks.push_back( - [callback, isolate](window_proc_delegate::WindowsMessage* message) { - // Enter the Dart isolate before calling the callback - Dart_Isolate previous = Dart_CurrentIsolate_DL(); - if (previous != isolate) { - if (previous) { - Dart_ExitIsolate_DL(); - } - Dart_EnterIsolate_DL(isolate); - } - - callback(message); - - // Restore previous isolate - Dart_Isolate current = Dart_CurrentIsolate_DL(); - if (previous != isolate) { - if (current) { - Dart_ExitIsolate_DL(); - } - if (previous) { - Dart_EnterIsolate_DL(previous); - } - } - }); - } - } - return callbacks; -} - -intptr_t WindowProcDelegateInitDartApi(void* data) { - return Dart_InitializeApiDL(data); -} From 43a565f042967a28a7ae0d09fd6fddff5b700895 Mon Sep 17 00:00:00 2001 From: boyan01 <17426470+boyan01@users.noreply.github.com> Date: Sun, 28 Dec 2025 22:12:01 +0800 Subject: [PATCH 2/4] update --- .../src/window_proc_delegate_internal.dart | 29 +++++++++++++++++-- .../lib/window_proc_delegate.dart | 2 ++ .../windows/window_proc_delegate_plugin.cpp | 4 +-- .../windows/window_proc_delegate_plugin.h | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart b/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart index 432a57f..b504da6 100644 --- a/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart +++ b/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart @@ -34,6 +34,8 @@ external void setCallback( bool _initialized = false; bool _dartApiInitialized = false; +bool _engineIdInitialized = false; +final MethodChannel _channel = MethodChannel('window_proc_delegate'); void ensureNativeLibraryInitialized() { if (_dartApiInitialized) return; @@ -52,6 +54,29 @@ void ensureNativeLibraryInitialized() { } } +/// Ensures the plugin's engine ID is initialized. +/// +/// This method registers the current engine ID with the native plugin. +/// It can be called early in application startup to ensure the plugin +/// is ready before any delegates are registered. +/// +/// If not called explicitly, the engine ID will be set automatically +/// when the first delegate is registered. +Future ensureInitializeEngineId() async { + if (!Platform.isWindows) return; + + if (_engineIdInitialized) return; + + _engineIdInitialized = true; + final int engineId = PlatformDispatcher.instance.engineId!; + try { + await _channel.invokeMethod('setEngineId', engineId); + } catch (e) { + debugPrint('Failed to set engine ID: $e'); + rethrow; + } +} + void initialize( List delegates, void Function(ffi.Pointer) handleWindowProc, @@ -73,8 +98,8 @@ void initialize( final int engineId = PlatformDispatcher.instance.engineId!; setCallback(engineId, nativeCallable.nativeFunction); - final channel = MethodChannel('window_proc_delegate'); - channel.invokeMethod('setEngineId', engineId); + // Set engine ID asynchronously (fire-and-forget with error handling) + ensureInitializeEngineId(); } catch (e) { debugPrint('Failed to set callback: $e'); } diff --git a/packages/window_proc_delegate/lib/window_proc_delegate.dart b/packages/window_proc_delegate/lib/window_proc_delegate.dart index 1e0e188..06e0ed7 100644 --- a/packages/window_proc_delegate/lib/window_proc_delegate.dart +++ b/packages/window_proc_delegate/lib/window_proc_delegate.dart @@ -2,6 +2,8 @@ import 'dart:ffi' as ffi; import 'src/windows_message.dart'; import 'src/window_proc_delegate_internal.dart' as internal; +export 'src/window_proc_delegate_internal.dart' show ensureInitializeEngineId; + /// Signature for a WindowProc delegate callback. /// /// The callback receives the window message parameters: diff --git a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp index 73be1cf..e2a624d 100644 --- a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp +++ b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp @@ -60,8 +60,8 @@ WindowProcDelegatePlugin::WindowProcDelegatePlugin( } WindowProcDelegatePlugin::~WindowProcDelegatePlugin() { - if (engine_id_ != -1) { - UnregisterPlugin(engine_id_); + if (engine_id_.has_value()) { + UnregisterPlugin(*engine_id_); } registrar_->UnregisterTopLevelWindowProcDelegate(window_proc_delegate_id_); } diff --git a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h index e295dbe..f1376c5 100644 --- a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h +++ b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.h @@ -74,7 +74,7 @@ class WindowProcDelegatePlugin : public flutter::Plugin { private: flutter::PluginRegistrarWindows* registrar_; int window_proc_delegate_id_; - int64_t engine_id_ = -1; + std::optional engine_id_; DartWindowProcCallbackC callback_ = nullptr; Dart_Isolate isolate_ = nullptr; std::mutex mutex_; From e6c085833c229a61be2d167e5c28ca74a0e8ad65 Mon Sep 17 00:00:00 2001 From: boyan01 <17426470+boyan01@users.noreply.github.com> Date: Sun, 28 Dec 2025 22:21:14 +0800 Subject: [PATCH 3/4] feat: update version to 0.0.3 and fix engine ID initialization --- packages/window_proc_delegate/CHANGELOG.md | 3 +++ packages/window_proc_delegate/example/pubspec.lock | 2 +- .../lib/src/window_proc_delegate_internal.dart | 2 +- packages/window_proc_delegate/pubspec.yaml | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/window_proc_delegate/CHANGELOG.md b/packages/window_proc_delegate/CHANGELOG.md index 1e8735c..0cb171b 100644 --- a/packages/window_proc_delegate/CHANGELOG.md +++ b/packages/window_proc_delegate/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.3 +* Fix crash on multi engine + ## 0.0.2 * Removed engine-specific message restriction - messages are now delivered to all registered delegates * Fixed crash issue when unregistering delegates diff --git a/packages/window_proc_delegate/example/pubspec.lock b/packages/window_proc_delegate/example/pubspec.lock index de5e796..472bcfb 100644 --- a/packages/window_proc_delegate/example/pubspec.lock +++ b/packages/window_proc_delegate/example/pubspec.lock @@ -277,7 +277,7 @@ packages: path: ".." relative: true source: path - version: "0.0.2" + version: "0.0.3" sdks: dart: ">=3.10.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart b/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart index b504da6..4be01c7 100644 --- a/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart +++ b/packages/window_proc_delegate/lib/src/window_proc_delegate_internal.dart @@ -67,10 +67,10 @@ Future ensureInitializeEngineId() async { if (_engineIdInitialized) return; - _engineIdInitialized = true; final int engineId = PlatformDispatcher.instance.engineId!; try { await _channel.invokeMethod('setEngineId', engineId); + _engineIdInitialized = true; } catch (e) { debugPrint('Failed to set engine ID: $e'); rethrow; diff --git a/packages/window_proc_delegate/pubspec.yaml b/packages/window_proc_delegate/pubspec.yaml index 5c7044a..04731e3 100644 --- a/packages/window_proc_delegate/pubspec.yaml +++ b/packages/window_proc_delegate/pubspec.yaml @@ -1,6 +1,6 @@ name: window_proc_delegate description: A Flutter plugin that allows you to hook into Windows WindowProc messages from Dart code. -version: 0.0.2 +version: 0.0.3 homepage: https://github.com/boyan01/packages environment: From 77f79200d27aab0cc8e5b8260b32ce38b24e40b5 Mon Sep 17 00:00:00 2001 From: boyan01 <17426470+boyan01@users.noreply.github.com> Date: Sun, 28 Dec 2025 22:29:07 +0800 Subject: [PATCH 4/4] feat: simplify engine ID handling in HandleMethodCall --- .../windows/window_proc_delegate_plugin.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp index e2a624d..1e4c939 100644 --- a/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp +++ b/packages/window_proc_delegate/windows/window_proc_delegate_plugin.cpp @@ -71,13 +71,10 @@ void WindowProcDelegatePlugin::HandleMethodCall( std::unique_ptr> result) { if (method_call.method_name().compare("setEngineId") == 0) { const auto* arguments = method_call.arguments(); - if (const auto* engine_id = std::get_if(arguments)) { - engine_id_ = *engine_id; - RegisterPlugin(engine_id_, this); - result->Success(); - } else { - result->Error("INVALID_ARGUMENT", "Engine ID must be an integer"); - } + auto engine_id = arguments->LongValue(); + engine_id_ = engine_id; + RegisterPlugin(engine_id, this); + result->Success(); } else { result->NotImplemented(); }