Implement Regular Windows for the win32 framework + add an example application for regular windows (#173715)

## What's new?
- Implement and test `_window_win32.dart`, the Win32 implementation of
`_window.dart` :tada:
- Wrote a bunch of tests in `window_win32_test.dart` which uses a mock
API barrier to mock the native Win32 layer
- Update `BaseWindowController` to extend `ChangeNotifier` and use it to
inform the `WindowScope` of when things change
- Made `RegularWindowController.empty()` a non-internal constructor, as
it is needed by implementations
- Added a _large_ example application for windowing where users can test
out different windowing concepts and see how they work!

To test, simply run the tests or try out the example app!

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
diff --git a/.ci.yaml b/.ci.yaml
index b1ec9d5..7cb993f 100644
--- a/.ci.yaml
+++ b/.ci.yaml
@@ -6987,6 +6987,20 @@
         ["devicelab", "hostonly", "windows", "arm64"]
       task_name: windows_startup_test
 
+  - name: Windows windowing_test
+    recipe: devicelab/devicelab_drone
+    presubmit: true
+    bringup: true
+    timeout: 60
+    properties:
+      dependencies: >-
+        [
+          {"dependency": "vs_build", "version": "version:vs2019"}
+        ]
+      tags: >
+        ["devicelab", "hostonly", "windows"]
+      task_name: windowing_test_windows
+
   - name: Windows flutter_tool_startup__windows
     recipe: devicelab/devicelab_drone
     presubmit: false
diff --git a/TESTOWNERS b/TESTOWNERS
index c8dfc6a..77b58aa 100644
--- a/TESTOWNERS
+++ b/TESTOWNERS
@@ -304,6 +304,7 @@
 /dev/devicelab/bin/tasks/windows_desktop_impeller.dart @jonahwilliams @flutter/engine
 /dev/devicelab/bin/tasks/windows_home_scroll_perf__timeline_summary.dart @jonahwilliams @flutter/engine
 /dev/devicelab/bin/tasks/windows_startup_test.dart @loic-sharma @flutter/desktop
+/dev/devicelab/bin/tasks/windowing_test_windows.dart @mattkae @flutter/desktop
 /dev/devicelab/bin/tasks/mac_desktop_impeller.dart @jonahwilliams @flutter/engine
 /dev/devicelab/bin/tasks/linux_desktop_impeller.dart @jonahwilliams @flutter/engine
 /dev/devicelab/bin/tasks/linux_feature_flags_test.dart @loic-sharma @flutter/desktop
diff --git a/dev/devicelab/bin/tasks/windowing_test_windows.dart b/dev/devicelab/bin/tasks/windowing_test_windows.dart
new file mode 100644
index 0000000..d682f2f
--- /dev/null
+++ b/dev/devicelab/bin/tasks/windowing_test_windows.dart
@@ -0,0 +1,12 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter_devicelab/framework/devices.dart';
+import 'package:flutter_devicelab/framework/framework.dart';
+import 'package:flutter_devicelab/tasks/integration_tests.dart';
+
+Future<void> main() async {
+  deviceOperatingSystem = DeviceOperatingSystem.windows;
+  await task(createWindowingDriverTest());
+}
diff --git a/dev/devicelab/lib/tasks/integration_tests.dart b/dev/devicelab/lib/tasks/integration_tests.dart
index bae536b..f95b931 100644
--- a/dev/devicelab/lib/tasks/integration_tests.dart
+++ b/dev/devicelab/lib/tasks/integration_tests.dart
@@ -221,6 +221,16 @@
   ).call;
 }
 
+TaskFunction createWindowingDriverTest() {
+  return () async {
+    await flutter('config', options: const <String>['--enable-windowing']);
+    return DriverTest(
+      '${flutterDirectory.path}/dev/integration_tests/windowing_test',
+      'lib/main.dart',
+    ).call();
+  };
+}
+
 TaskFunction createWideGamutTest() {
   return IntegrationTest(
     '${flutterDirectory.path}/dev/integration_tests/wide_gamut_test',
diff --git a/dev/integration_tests/windowing_test/.gitignore b/dev/integration_tests/windowing_test/.gitignore
new file mode 100644
index 0000000..3820a95
--- /dev/null
+++ b/dev/integration_tests/windowing_test/.gitignore
@@ -0,0 +1,45 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+/coverage/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/dev/integration_tests/windowing_test/.metadata b/dev/integration_tests/windowing_test/.metadata
new file mode 100644
index 0000000..873e782
--- /dev/null
+++ b/dev/integration_tests/windowing_test/.metadata
@@ -0,0 +1,26 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "e27f0a6943e07b6d3420fb185432705b87101fa8"
+  channel: "[user-branch]"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+  platforms:
+    - platform: windows
+      create_revision: e27f0a6943e07b6d3420fb185432705b87101fa8
+      base_revision: e27f0a6943e07b6d3420fb185432705b87101fa8
+
+  # User provided section
+
+  # List of Local paths (relative to this file) that should be
+  # ignored by the migrate tool.
+  #
+  # Files that are not part of the templates will be ignored by default.
+  unmanaged_files:
+    - 'lib/main.dart'
diff --git a/dev/integration_tests/windowing_test/README.md b/dev/integration_tests/windowing_test/README.md
new file mode 100644
index 0000000..c2808e4
--- /dev/null
+++ b/dev/integration_tests/windowing_test/README.md
@@ -0,0 +1,10 @@
+# windowing_test
+
+Integration tests for windowing.
+
+## Run
+From this directory, run:
+
+```sh
+flutter drive -t .\lib\main.dart --driver .\test_driver\windowing_test.dart
+```
diff --git a/dev/integration_tests/windowing_test/analysis_options.yaml b/dev/integration_tests/windowing_test/analysis_options.yaml
new file mode 100644
index 0000000..f16eead
--- /dev/null
+++ b/dev/integration_tests/windowing_test/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+linter:
+  rules:
\ No newline at end of file
diff --git a/dev/integration_tests/windowing_test/lib/main.dart b/dev/integration_tests/windowing_test/lib/main.dart
new file mode 100644
index 0000000..5ef97c9
--- /dev/null
+++ b/dev/integration_tests/windowing_test/lib/main.dart
@@ -0,0 +1,162 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/_window.dart';
+import 'package:flutter_driver/driver_extension.dart';
+
+class _MainRegularWindowControllerDelegate
+    extends RegularWindowControllerDelegate {
+  @override
+  void onWindowDestroyed() {
+    super.onWindowDestroyed();
+
+    exit(0);
+  }
+}
+
+late final RegularWindowController controller;
+
+void main() {
+  final Completer<void> windowCreated = Completer();
+  enableFlutterDriverExtension(
+    handler: (String? message) async {
+      await windowCreated.future;
+      if (message == null) {
+        return '';
+      }
+
+      final jsonMap = jsonDecode(message);
+      if (!jsonMap.containsKey('type')) {
+        throw ArgumentError('Message must contain a "type" field.');
+      }
+
+      if (jsonMap['type'] == 'get_size') {
+        return jsonEncode({
+          'width': controller.contentSize.width,
+          'height': controller.contentSize.height,
+        });
+      } else if (jsonMap['type'] == 'set_size') {
+        final Size size = Size(
+          jsonMap['width'].toDouble(),
+          jsonMap['height'].toDouble(),
+        );
+        controller.setSize(size);
+      } else if (jsonMap['type'] == 'set_constraints') {
+        final BoxConstraints constraints = BoxConstraints(
+          minWidth: jsonMap['min_width'].toDouble(),
+          minHeight: jsonMap['min_height'].toDouble(),
+          maxWidth: jsonMap['max_width'].toDouble(),
+          maxHeight: jsonMap['max_height'].toDouble(),
+        );
+        controller.setConstraints(constraints);
+      } else if (jsonMap['type'] == 'set_fullscreen') {
+        controller.setFullscreen(true);
+      } else if (jsonMap['type'] == 'unset_fullscreen') {
+        controller.setFullscreen(false);
+      } else if (jsonMap['type'] == 'get_fullscreen') {
+        return jsonEncode({'isFullscreen': controller.isFullscreen});
+      } else if (jsonMap['type'] == 'set_maximized') {
+        controller.setMaximized(true);
+      } else if (jsonMap['type'] == 'unset_maximized') {
+        controller.setMaximized(false);
+      } else if (jsonMap['type'] == 'get_maximized') {
+        return jsonEncode({'isMaximized': controller.isMaximized});
+      } else if (jsonMap['type'] == 'set_minimized') {
+        controller.setMinimized(true);
+      } else if (jsonMap['type'] == 'unset_minimized') {
+        controller.setMinimized(false);
+      } else if (jsonMap['type'] == 'get_minimized') {
+        return jsonEncode({'isMinimized': controller.isMinimized});
+      } else if (jsonMap['type'] == 'set_title') {
+        controller.setTitle(jsonMap['title']);
+      } else if (jsonMap['type'] == 'get_title') {
+        return jsonEncode({'title': controller.title});
+      } else if (jsonMap['type'] == 'set_activated') {
+        controller.activate();
+      } else if (jsonMap['type'] == 'get_activated') {
+        return jsonEncode({'isActivated': controller.isActivated});
+      } else {
+        throw ArgumentError('Unknown message type: ${jsonMap['type']}');
+      }
+
+      return '';
+    },
+  );
+  controller = RegularWindowController(
+    preferredSize: Size(640, 480),
+    title: 'Integration Test',
+    delegate: _MainRegularWindowControllerDelegate(),
+  );
+  windowCreated.complete();
+
+  runWidget(RegularWindow(controller: controller, child: MyApp()));
+}
+
+class MyApp extends StatelessWidget {
+  const MyApp({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'Flutter Demo',
+      theme: ThemeData(
+        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+      ),
+      home: const MyHomePage(title: 'Flutter Demo Home Page'),
+    );
+  }
+}
+
+class MyHomePage extends StatefulWidget {
+  const MyHomePage({super.key, required this.title});
+
+  final String title;
+
+  @override
+  State<MyHomePage> createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+  int _counter = 0;
+
+  void _incrementCounter() {
+    setState(() {
+      _counter++;
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+        title: Text(widget.title),
+      ),
+      body: Center(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: <Widget>[
+            const Text('You have pushed the button this many times:'),
+            Text(
+              '$_counter',
+              style: Theme.of(context).textTheme.headlineMedium,
+            ),
+          ],
+        ),
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: _incrementCounter,
+        tooltip: 'Increment',
+        child: const Icon(Icons.add),
+      ),
+    );
+  }
+}
diff --git a/dev/integration_tests/windowing_test/pubspec.yaml b/dev/integration_tests/windowing_test/pubspec.yaml
new file mode 100644
index 0000000..b05793b
--- /dev/null
+++ b/dev/integration_tests/windowing_test/pubspec.yaml
@@ -0,0 +1,22 @@
+name: windowing_test
+description: Flutter windowing integration tests.
+
+environment:
+  sdk: ^3.8.0-0
+
+dependencies:
+  flutter:
+    sdk: flutter
+  flutter_driver:
+    sdk: flutter
+  integration_test:
+    sdk: flutter
+  test: any
+
+  path: any
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+
+# PUBSPEC CHECKSUM: 77jv2r
diff --git a/dev/integration_tests/windowing_test/test_driver/main_test.dart b/dev/integration_tests/windowing_test/test_driver/main_test.dart
new file mode 100644
index 0000000..872f360
--- /dev/null
+++ b/dev/integration_tests/windowing_test/test_driver/main_test.dart
@@ -0,0 +1,129 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+void main() {
+  group('end-to-end test', () {
+    late final FlutterDriver driver;
+
+    setUpAll(() async {
+      driver = await FlutterDriver.connect();
+    });
+
+    tearDownAll(() async {
+      await driver.close();
+    });
+
+    test('Can set and get title', () async {
+      await driver.requestData(
+        jsonEncode({'type': 'set_title', 'title': 'Hello World'}),
+      );
+      final response = await driver.requestData(
+        jsonEncode({'type': 'get_title'}),
+      );
+      final data = jsonDecode(response);
+      expect(data['title'], 'Hello World');
+    }, timeout: Timeout.none);
+
+    test('Initial controller size is correct', () async {
+      final response = await driver.requestData(
+        jsonEncode({'type': 'get_size'}),
+      );
+      final data = jsonDecode(response);
+      expect(data["width"], 640);
+      expect(data["height"], 480);
+    }, timeout: Timeout.none);
+
+    test('Can set and get size', () async {
+      await driver.requestData(
+        jsonEncode({'type': 'set_size', 'width': 800, 'height': 600}),
+      );
+      final response = await driver.requestData(
+        jsonEncode({'type': 'get_size'}),
+      );
+      final data = jsonDecode(response);
+      expect(data["width"], 800);
+      expect(data["height"], 600);
+    }, timeout: Timeout.none);
+
+    test('Can set constraints and see the resize', () async {
+      await driver.requestData(
+        jsonEncode({
+          'type': 'set_constraints',
+          'min_width': 0,
+          'min_height': 0,
+          'max_width': 500,
+          'max_height': 501,
+        }),
+      );
+      final response = await driver.requestData(
+        jsonEncode({'type': 'get_size'}),
+      );
+      final data = jsonDecode(response);
+      expect(data["width"], 500);
+      expect(data["height"], 501);
+    }, timeout: Timeout.none);
+
+    test('Can set and get fullscreen', () async {
+      await driver.requestData(jsonEncode({'type': 'set_fullscreen'}));
+      var response = await driver.requestData(
+        jsonEncode({'type': 'get_fullscreen'}),
+      );
+      var data = jsonDecode(response);
+      expect(data["isFullscreen"], true);
+
+      await driver.requestData(jsonEncode({'type': 'unset_fullscreen'}));
+      response = await driver.requestData(
+        jsonEncode({'type': 'get_fullscreen'}),
+      );
+      data = jsonDecode(response);
+      expect(data["isFullscreen"], false);
+    }, timeout: Timeout.none);
+
+    test('Can set and get maximized', () async {
+      await driver.requestData(jsonEncode({'type': 'set_maximized'}));
+      var response = await driver.requestData(
+        jsonEncode({'type': 'get_maximized'}),
+      );
+      var data = jsonDecode(response);
+      expect(data["isMaximized"], true);
+
+      await driver.requestData(jsonEncode({'type': 'unset_maximized'}));
+      response = await driver.requestData(
+        jsonEncode({'type': 'get_maximized'}),
+      );
+      data = jsonDecode(response);
+      expect(data["isMaximized"], false);
+    }, timeout: Timeout.none);
+
+    test('Can set and get minimized', () async {
+      await driver.requestData(jsonEncode({'type': 'set_minimized'}));
+      var response = await driver.requestData(
+        jsonEncode({'type': 'get_minimized'}),
+      );
+      var data = jsonDecode(response);
+      expect(data["isMinimized"], true);
+
+      await driver.requestData(jsonEncode({'type': 'unset_minimized'}));
+      response = await driver.requestData(
+        jsonEncode({'type': 'get_minimized'}),
+      );
+      data = jsonDecode(response);
+      expect(data["isMinimized"], false);
+    }, timeout: Timeout.none);
+
+    test('Can set and get activated', () async {
+      await driver.requestData(jsonEncode({'type': 'set_activated'}));
+      final response = await driver.requestData(
+        jsonEncode({'type': 'get_activated'}),
+      );
+      final data = jsonDecode(response);
+      expect(data["isActivated"], true);
+    }, timeout: Timeout.none);
+  });
+}
diff --git a/dev/integration_tests/windowing_test/windows/.gitignore b/dev/integration_tests/windowing_test/windows/.gitignore
new file mode 100644
index 0000000..d492d0d
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/.gitignore
@@ -0,0 +1,17 @@
+flutter/ephemeral/
+
+# Visual Studio user-specific files.
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Visual Studio build-related files.
+x64/
+x86/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
diff --git a/dev/integration_tests/windowing_test/windows/CMakeLists.txt b/dev/integration_tests/windowing_test/windows/CMakeLists.txt
new file mode 100644
index 0000000..4e85c1d
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/CMakeLists.txt
@@ -0,0 +1,108 @@
+# Project-level configuration.
+cmake_minimum_required(VERSION 3.14)
+project(windowing_test LANGUAGES CXX)
+
+# The name of the executable created for the application. Change this to change
+# the on-disk name of your application.
+set(BINARY_NAME "windowing_test")
+
+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
+# versions of CMake.
+cmake_policy(VERSION 3.14...3.25)
+
+# Define build configuration option.
+get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(IS_MULTICONFIG)
+  set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
+    CACHE STRING "" FORCE)
+else()
+  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+    set(CMAKE_BUILD_TYPE "Debug" CACHE
+      STRING "Flutter build mode" FORCE)
+    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+      "Debug" "Profile" "Release")
+  endif()
+endif()
+# Define settings for the Profile build mode.
+set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
+set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
+set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
+set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
+
+# Use Unicode for all projects.
+add_definitions(-DUNICODE -D_UNICODE)
+
+# Compilation settings that should be applied to most targets.
+#
+# Be cautious about adding new options here, as plugins use this function by
+# default. In most cases, you should add new options to specific targets instead
+# of modifying this function.
+function(APPLY_STANDARD_SETTINGS TARGET)
+  target_compile_features(${TARGET} PUBLIC cxx_std_17)
+  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
+  target_compile_options(${TARGET} PRIVATE /EHsc)
+  target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
+  target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
+endfunction()
+
+# Flutter library and tool build rules.
+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
+add_subdirectory(${FLUTTER_MANAGED_DIR})
+
+# Application build; see runner/CMakeLists.txt.
+add_subdirectory("runner")
+
+
+# Generated plugin build rules, which manage building the plugins and adding
+# them to the application.
+include(flutter/generated_plugins.cmake)
+
+
+# === Installation ===
+# Support files are copied into place next to the executable, so that it can
+# run in place. This is done instead of making a separate bundle (as on Linux)
+# so that building and running from within Visual Studio will work.
+set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
+# Make the "install" step default, as it's required to run.
+set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
+endif()
+
+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
+
+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+  COMPONENT Runtime)
+
+if(PLUGIN_BUNDLED_LIBRARIES)
+  install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
+    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+    COMPONENT Runtime)
+endif()
+
+# Copy the native assets provided by the build.dart from all packages.
+set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
+install(DIRECTORY "${NATIVE_ASSETS_DIR}"
+   DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+   COMPONENT Runtime)
+
+# Fully re-copy the assets directory on each build to avoid having stale files
+# from a previous install.
+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
+install(CODE "
+  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
+  " COMPONENT Runtime)
+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
+  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
+
+# Install the AOT library on non-Debug builds only.
+install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  CONFIGURATIONS Profile;Release
+  COMPONENT Runtime)
diff --git a/dev/integration_tests/windowing_test/windows/flutter/CMakeLists.txt b/dev/integration_tests/windowing_test/windows/flutter/CMakeLists.txt
new file mode 100644
index 0000000..903f489
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/flutter/CMakeLists.txt
@@ -0,0 +1,109 @@
+# This file controls Flutter-level build steps. It should not be edited.
+cmake_minimum_required(VERSION 3.14)
+
+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
+
+# Configuration provided via flutter tool.
+include(${EPHEMERAL_DIR}/generated_config.cmake)
+
+# TODO: Move the rest of this into files in ephemeral. See
+# https://github.com/flutter/flutter/issues/57146.
+set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
+
+# Set fallback configurations for older versions of the flutter tool.
+if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
+  set(FLUTTER_TARGET_PLATFORM "windows-x64")
+endif()
+
+# === Flutter Library ===
+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
+
+# Published to parent scope for install step.
+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
+set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
+
+list(APPEND FLUTTER_LIBRARY_HEADERS
+  "flutter_export.h"
+  "flutter_windows.h"
+  "flutter_messenger.h"
+  "flutter_plugin_registrar.h"
+  "flutter_texture_registrar.h"
+)
+list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
+add_library(flutter INTERFACE)
+target_include_directories(flutter INTERFACE
+  "${EPHEMERAL_DIR}"
+)
+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
+add_dependencies(flutter flutter_assemble)
+
+# === Wrapper ===
+list(APPEND CPP_WRAPPER_SOURCES_CORE
+  "core_implementations.cc"
+  "standard_codec.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
+  "plugin_registrar.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_APP
+  "flutter_engine.cc"
+  "flutter_view_controller.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
+
+# Wrapper sources needed for a plugin.
+add_library(flutter_wrapper_plugin STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+)
+apply_standard_settings(flutter_wrapper_plugin)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  POSITION_INDEPENDENT_CODE ON)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  CXX_VISIBILITY_PRESET hidden)
+target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
+target_include_directories(flutter_wrapper_plugin PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_plugin flutter_assemble)
+
+# Wrapper sources needed for the runner.
+add_library(flutter_wrapper_app STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
+apply_standard_settings(flutter_wrapper_app)
+target_link_libraries(flutter_wrapper_app PUBLIC flutter)
+target_include_directories(flutter_wrapper_app PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_app flutter_assemble)
+
+# === Flutter tool backend ===
+# _phony_ is a non-existent file to force this command to run every time,
+# since currently there's no way to get a full input/output list from the
+# flutter tool.
+set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
+set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
+add_custom_command(
+  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
+    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
+    ${CPP_WRAPPER_SOURCES_APP}
+    ${PHONY_OUTPUT}
+  COMMAND ${CMAKE_COMMAND} -E env
+    ${FLUTTER_TOOL_ENVIRONMENT}
+    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
+      ${FLUTTER_TARGET_PLATFORM} $<CONFIG>
+  VERBATIM
+)
+add_custom_target(flutter_assemble DEPENDS
+  "${FLUTTER_LIBRARY}"
+  ${FLUTTER_LIBRARY_HEADERS}
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
diff --git a/dev/integration_tests/windowing_test/windows/runner/CMakeLists.txt b/dev/integration_tests/windowing_test/windows/runner/CMakeLists.txt
new file mode 100644
index 0000000..394917c
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 3.14)
+project(runner LANGUAGES CXX)
+
+# Define the application target. To change its name, change BINARY_NAME in the
+# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
+# work.
+#
+# Any new source files that you add to the application should be added here.
+add_executable(${BINARY_NAME} WIN32
+  "flutter_window.cpp"
+  "main.cpp"
+  "utils.cpp"
+  "win32_window.cpp"
+  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
+  "Runner.rc"
+  "runner.exe.manifest"
+)
+
+# Apply the standard set of build settings. This can be removed for applications
+# that need different build settings.
+apply_standard_settings(${BINARY_NAME})
+
+# Add preprocessor definitions for the build version.
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
+
+# Disable Windows macros that collide with C++ standard library functions.
+target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
+
+# Add dependency libraries and include directories. Add any application-specific
+# dependencies here.
+target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
+target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
+target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+
+# Run the Flutter tool portions of the build. This must not be removed.
+add_dependencies(${BINARY_NAME} flutter_assemble)
diff --git a/dev/integration_tests/windowing_test/windows/runner/Runner.rc b/dev/integration_tests/windowing_test/windows/runner/Runner.rc
new file mode 100644
index 0000000..88669f8
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/Runner.rc
@@ -0,0 +1,121 @@
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#include ""winres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
+#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
+#else
+#define VERSION_AS_NUMBER 1,0,0,0
+#endif
+
+#if defined(FLUTTER_VERSION)
+#define VERSION_AS_STRING FLUTTER_VERSION
+#else
+#define VERSION_AS_STRING "1.0.0"
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_AS_NUMBER
+ PRODUCTVERSION VERSION_AS_NUMBER
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "com.example" "\0"
+            VALUE "FileDescription", "windowing_test" "\0"
+            VALUE "FileVersion", VERSION_AS_STRING "\0"
+            VALUE "InternalName", "windowing_test" "\0"
+            VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0"
+            VALUE "OriginalFilename", "windowing_test.exe" "\0"
+            VALUE "ProductName", "windowing_test" "\0"
+            VALUE "ProductVersion", VERSION_AS_STRING "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/dev/integration_tests/windowing_test/windows/runner/flutter_window.cpp b/dev/integration_tests/windowing_test/windows/runner/flutter_window.cpp
new file mode 100644
index 0000000..252aa26
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/flutter_window.cpp
@@ -0,0 +1,75 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "flutter_window.h"
+
+#include <optional>
+
+#include "flutter/generated_plugin_registrant.h"
+
+FlutterWindow::FlutterWindow(const flutter::DartProject& project)
+    : project_(project) {}
+
+FlutterWindow::~FlutterWindow() {}
+
+bool FlutterWindow::OnCreate() {
+  if (!Win32Window::OnCreate()) {
+    return false;
+  }
+
+  RECT frame = GetClientArea();
+
+  // The size here must match the window dimensions to avoid unnecessary surface
+  // creation / destruction in the startup path.
+  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
+      frame.right - frame.left, frame.bottom - frame.top, project_);
+  // Ensure that basic setup of the controller was successful.
+  if (!flutter_controller_->engine() || !flutter_controller_->view()) {
+    return false;
+  }
+  RegisterPlugins(flutter_controller_->engine());
+  SetChildContent(flutter_controller_->view()->GetNativeWindow());
+
+  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
+  // window is shown. It is a no-op if the first frame hasn't completed yet.
+  flutter_controller_->ForceRedraw();
+
+  return true;
+}
+
+void FlutterWindow::OnDestroy() {
+  if (flutter_controller_) {
+    flutter_controller_ = nullptr;
+  }
+
+  Win32Window::OnDestroy();
+}
+
+LRESULT
+FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
+                              WPARAM const wparam,
+                              LPARAM const lparam) noexcept {
+  // Give Flutter, including plugins, an opportunity to handle window messages.
+  if (flutter_controller_) {
+    std::optional<LRESULT> result =
+        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
+                                                      lparam);
+    if (result) {
+      return *result;
+    }
+  }
+
+  switch (message) {
+    case WM_FONTCHANGE:
+      flutter_controller_->engine()->ReloadSystemFonts();
+      break;
+  }
+
+  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
+}
diff --git a/dev/integration_tests/windowing_test/windows/runner/flutter_window.h b/dev/integration_tests/windowing_test/windows/runner/flutter_window.h
new file mode 100644
index 0000000..bbc5836
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/flutter_window.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef RUNNER_FLUTTER_WINDOW_H_
+#define RUNNER_FLUTTER_WINDOW_H_
+
+#include <flutter/dart_project.h>
+#include <flutter/flutter_view_controller.h>
+
+#include <memory>
+
+#include "win32_window.h"
+
+// A window that does nothing but host a Flutter view.
+class FlutterWindow : public Win32Window {
+ public:
+  // Creates a new FlutterWindow hosting a Flutter view running |project|.
+  explicit FlutterWindow(const flutter::DartProject& project);
+  virtual ~FlutterWindow();
+
+ protected:
+  // Win32Window:
+  bool OnCreate() override;
+  void OnDestroy() override;
+  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
+                         LPARAM const lparam) noexcept override;
+
+ private:
+  // The project to run.
+  flutter::DartProject project_;
+
+  // The Flutter instance hosted by this window.
+  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
+};
+
+#endif  // RUNNER_FLUTTER_WINDOW_H_
diff --git a/dev/integration_tests/windowing_test/windows/runner/main.cpp b/dev/integration_tests/windowing_test/windows/runner/main.cpp
new file mode 100644
index 0000000..5621ff1
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/main.cpp
@@ -0,0 +1,47 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <flutter/dart_project.h>
+#include <flutter/flutter_view_controller.h>
+#include <windows.h>
+
+#include "flutter_window.h"
+#include "utils.h"
+
+int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
+                      _In_ wchar_t *command_line, _In_ int show_command) {
+  // Attach to console when present (e.g., 'flutter run') or create a
+  // new console when running with a debugger.
+  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
+    CreateAndAttachConsole();
+  }
+
+  // Initialize COM, so that it is available for use in the library and/or
+  // plugins.
+  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+
+  flutter::DartProject project(L"data");
+
+  std::vector<std::string> command_line_arguments =
+      GetCommandLineArguments();
+
+  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
+
+  FlutterWindow window(project);
+  Win32Window::Point origin(10, 10);
+  Win32Window::Size size(1280, 720);
+  if (!window.Create(L"windowing_test", origin, size)) {
+    return EXIT_FAILURE;
+  }
+  window.SetQuitOnClose(true);
+
+  ::MSG msg;
+  while (::GetMessage(&msg, nullptr, 0, 0)) {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+  }
+
+  ::CoUninitialize();
+  return EXIT_SUCCESS;
+}
diff --git a/dev/integration_tests/windowing_test/windows/runner/resource.h b/dev/integration_tests/windowing_test/windows/runner/resource.h
new file mode 100644
index 0000000..c245ff1
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/resource.h
@@ -0,0 +1,20 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Runner.rc
+//
+#define IDI_APP_ICON                    101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        102
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/dev/integration_tests/windowing_test/windows/runner/runner.exe.manifest b/dev/integration_tests/windowing_test/windows/runner/runner.exe.manifest
new file mode 100644
index 0000000..153653e
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/runner.exe.manifest
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
+    </windowsSettings>
+  </application>
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- Windows 10 and Windows 11 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+    </application>
+  </compatibility>
+</assembly>
diff --git a/dev/integration_tests/windowing_test/windows/runner/utils.cpp b/dev/integration_tests/windowing_test/windows/runner/utils.cpp
new file mode 100644
index 0000000..02f4362
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/utils.cpp
@@ -0,0 +1,69 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "utils.h"
+
+#include <flutter_windows.h>
+#include <io.h>
+#include <stdio.h>
+#include <windows.h>
+
+#include <iostream>
+
+void CreateAndAttachConsole() {
+  if (::AllocConsole()) {
+    FILE *unused;
+    if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
+      _dup2(_fileno(stdout), 1);
+    }
+    if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
+      _dup2(_fileno(stdout), 2);
+    }
+    std::ios::sync_with_stdio();
+    FlutterDesktopResyncOutputStreams();
+  }
+}
+
+std::vector<std::string> GetCommandLineArguments() {
+  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
+  int argc;
+  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
+  if (argv == nullptr) {
+    return std::vector<std::string>();
+  }
+
+  std::vector<std::string> command_line_arguments;
+
+  // Skip the first argument as it's the binary name.
+  for (int i = 1; i < argc; i++) {
+    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
+  }
+
+  ::LocalFree(argv);
+
+  return command_line_arguments;
+}
+
+std::string Utf8FromUtf16(const wchar_t* utf16_string) {
+  if (utf16_string == nullptr) {
+    return std::string();
+  }
+  unsigned int target_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      -1, nullptr, 0, nullptr, nullptr)
+    -1; // remove the trailing null character
+  int input_length = (int)wcslen(utf16_string);
+  std::string utf8_string;
+  if (target_length == 0 || target_length > utf8_string.max_size()) {
+    return utf8_string;
+  }
+  utf8_string.resize(target_length);
+  int converted_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      input_length, utf8_string.data(), target_length, nullptr, nullptr);
+  if (converted_length == 0) {
+    return std::string();
+  }
+  return utf8_string;
+}
diff --git a/dev/integration_tests/windowing_test/windows/runner/utils.h b/dev/integration_tests/windowing_test/windows/runner/utils.h
new file mode 100644
index 0000000..54414c9
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/utils.h
@@ -0,0 +1,23 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef RUNNER_UTILS_H_
+#define RUNNER_UTILS_H_
+
+#include <string>
+#include <vector>
+
+// Creates a console for the process, and redirects stdout and stderr to
+// it for both the runner and the Flutter library.
+void CreateAndAttachConsole();
+
+// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
+// encoded in UTF-8. Returns an empty std::string on failure.
+std::string Utf8FromUtf16(const wchar_t* utf16_string);
+
+// Gets the command line arguments passed in as a std::vector<std::string>,
+// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
+std::vector<std::string> GetCommandLineArguments();
+
+#endif  // RUNNER_UTILS_H_
diff --git a/dev/integration_tests/windowing_test/windows/runner/win32_window.cpp b/dev/integration_tests/windowing_test/windows/runner/win32_window.cpp
new file mode 100644
index 0000000..14a183d
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/win32_window.cpp
@@ -0,0 +1,292 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "win32_window.h"
+
+#include <dwmapi.h>
+#include <flutter_windows.h>
+
+#include "resource.h"
+
+namespace {
+
+/// Window attribute that enables dark mode window decorations.
+///
+/// Redefined in case the developer's machine has a Windows SDK older than
+/// version 10.0.22000.0.
+/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
+
+constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
+
+/// Registry key for app theme preference.
+///
+/// A value of 0 indicates apps should use dark mode. A non-zero or missing
+/// value indicates apps should use light mode.
+constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
+  L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
+constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
+
+// The number of Win32Window objects that currently exist.
+static int g_active_window_count = 0;
+
+using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
+
+// Scale helper to convert logical scaler values to physical using passed in
+// scale factor
+int Scale(int source, double scale_factor) {
+  return static_cast<int>(source * scale_factor);
+}
+
+// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
+// This API is only needed for PerMonitor V1 awareness mode.
+void EnableFullDpiSupportIfAvailable(HWND hwnd) {
+  HMODULE user32_module = LoadLibraryA("User32.dll");
+  if (!user32_module) {
+    return;
+  }
+  auto enable_non_client_dpi_scaling =
+      reinterpret_cast<EnableNonClientDpiScaling*>(
+          GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
+  if (enable_non_client_dpi_scaling != nullptr) {
+    enable_non_client_dpi_scaling(hwnd);
+  }
+  FreeLibrary(user32_module);
+}
+
+}  // namespace
+
+// Manages the Win32Window's window class registration.
+class WindowClassRegistrar {
+ public:
+  ~WindowClassRegistrar() = default;
+
+  // Returns the singleton registrar instance.
+  static WindowClassRegistrar* GetInstance() {
+    if (!instance_) {
+      instance_ = new WindowClassRegistrar();
+    }
+    return instance_;
+  }
+
+  // Returns the name of the window class, registering the class if it hasn't
+  // previously been registered.
+  const wchar_t* GetWindowClass();
+
+  // Unregisters the window class. Should only be called if there are no
+  // instances of the window.
+  void UnregisterWindowClass();
+
+ private:
+  WindowClassRegistrar() = default;
+
+  static WindowClassRegistrar* instance_;
+
+  bool class_registered_ = false;
+};
+
+WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
+
+const wchar_t* WindowClassRegistrar::GetWindowClass() {
+  if (!class_registered_) {
+    WNDCLASS window_class{};
+    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
+    window_class.lpszClassName = kWindowClassName;
+    window_class.style = CS_HREDRAW | CS_VREDRAW;
+    window_class.cbClsExtra = 0;
+    window_class.cbWndExtra = 0;
+    window_class.hInstance = GetModuleHandle(nullptr);
+    window_class.hIcon =
+        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
+    window_class.hbrBackground = 0;
+    window_class.lpszMenuName = nullptr;
+    window_class.lpfnWndProc = Win32Window::WndProc;
+    RegisterClass(&window_class);
+    class_registered_ = true;
+  }
+  return kWindowClassName;
+}
+
+void WindowClassRegistrar::UnregisterWindowClass() {
+  UnregisterClass(kWindowClassName, nullptr);
+  class_registered_ = false;
+}
+
+Win32Window::Win32Window() {
+  ++g_active_window_count;
+}
+
+Win32Window::~Win32Window() {
+  --g_active_window_count;
+  Destroy();
+}
+
+bool Win32Window::Create(const std::wstring& title,
+                         const Point& origin,
+                         const Size& size) {
+  Destroy();
+
+  const wchar_t* window_class =
+      WindowClassRegistrar::GetInstance()->GetWindowClass();
+
+  const POINT target_point = {static_cast<LONG>(origin.x),
+                              static_cast<LONG>(origin.y)};
+  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
+  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
+  double scale_factor = dpi / 96.0;
+
+  HWND window = CreateWindow(
+      window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
+      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
+      Scale(size.width, scale_factor), Scale(size.height, scale_factor),
+      nullptr, nullptr, GetModuleHandle(nullptr), this);
+
+  if (!window) {
+    return false;
+  }
+
+  UpdateTheme(window);
+
+  return OnCreate();
+}
+
+bool Win32Window::Show() {
+  return ShowWindow(window_handle_, SW_SHOWNORMAL);
+}
+
+// static
+LRESULT CALLBACK Win32Window::WndProc(HWND const window,
+                                      UINT const message,
+                                      WPARAM const wparam,
+                                      LPARAM const lparam) noexcept {
+  if (message == WM_NCCREATE) {
+    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
+    SetWindowLongPtr(window, GWLP_USERDATA,
+                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
+
+    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
+    EnableFullDpiSupportIfAvailable(window);
+    that->window_handle_ = window;
+  } else if (Win32Window* that = GetThisFromHandle(window)) {
+    return that->MessageHandler(window, message, wparam, lparam);
+  }
+
+  return DefWindowProc(window, message, wparam, lparam);
+}
+
+LRESULT
+Win32Window::MessageHandler(HWND hwnd,
+                            UINT const message,
+                            WPARAM const wparam,
+                            LPARAM const lparam) noexcept {
+  switch (message) {
+    case WM_DESTROY:
+      window_handle_ = nullptr;
+      Destroy();
+      if (quit_on_close_) {
+        PostQuitMessage(0);
+      }
+      return 0;
+
+    case WM_DPICHANGED: {
+      auto newRectSize = reinterpret_cast<RECT*>(lparam);
+      LONG newWidth = newRectSize->right - newRectSize->left;
+      LONG newHeight = newRectSize->bottom - newRectSize->top;
+
+      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
+                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
+
+      return 0;
+    }
+    case WM_SIZE: {
+      RECT rect = GetClientArea();
+      if (child_content_ != nullptr) {
+        // Size and position the child window.
+        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
+                   rect.bottom - rect.top, TRUE);
+      }
+      return 0;
+    }
+
+    case WM_ACTIVATE:
+      if (child_content_ != nullptr) {
+        SetFocus(child_content_);
+      }
+      return 0;
+
+    case WM_DWMCOLORIZATIONCOLORCHANGED:
+      UpdateTheme(hwnd);
+      return 0;
+  }
+
+  return DefWindowProc(window_handle_, message, wparam, lparam);
+}
+
+void Win32Window::Destroy() {
+  OnDestroy();
+
+  if (window_handle_) {
+    DestroyWindow(window_handle_);
+    window_handle_ = nullptr;
+  }
+  if (g_active_window_count == 0) {
+    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
+  }
+}
+
+Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
+  return reinterpret_cast<Win32Window*>(
+      GetWindowLongPtr(window, GWLP_USERDATA));
+}
+
+void Win32Window::SetChildContent(HWND content) {
+  child_content_ = content;
+  SetParent(content, window_handle_);
+  RECT frame = GetClientArea();
+
+  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
+             frame.bottom - frame.top, true);
+
+  SetFocus(child_content_);
+}
+
+RECT Win32Window::GetClientArea() {
+  RECT frame;
+  GetClientRect(window_handle_, &frame);
+  return frame;
+}
+
+HWND Win32Window::GetHandle() {
+  return window_handle_;
+}
+
+void Win32Window::SetQuitOnClose(bool quit_on_close) {
+  quit_on_close_ = quit_on_close;
+}
+
+bool Win32Window::OnCreate() {
+  // No-op; provided for subclasses.
+  return true;
+}
+
+void Win32Window::OnDestroy() {
+  // No-op; provided for subclasses.
+}
+
+void Win32Window::UpdateTheme(HWND const window) {
+  DWORD light_mode;
+  DWORD light_mode_size = sizeof(light_mode);
+  LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
+                               kGetPreferredBrightnessRegValue,
+                               RRF_RT_REG_DWORD, nullptr, &light_mode,
+                               &light_mode_size);
+
+  if (result == ERROR_SUCCESS) {
+    BOOL enable_dark_mode = light_mode == 0;
+    DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
+                          &enable_dark_mode, sizeof(enable_dark_mode));
+  }
+}
diff --git a/dev/integration_tests/windowing_test/windows/runner/win32_window.h b/dev/integration_tests/windowing_test/windows/runner/win32_window.h
new file mode 100644
index 0000000..bb93e88
--- /dev/null
+++ b/dev/integration_tests/windowing_test/windows/runner/win32_window.h
@@ -0,0 +1,106 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef RUNNER_WIN32_WINDOW_H_
+#define RUNNER_WIN32_WINDOW_H_
+
+#include <windows.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+
+// A class abstraction for a high DPI-aware Win32 Window. Intended to be
+// inherited from by classes that wish to specialize with custom
+// rendering and input handling
+class Win32Window {
+ public:
+  struct Point {
+    unsigned int x;
+    unsigned int y;
+    Point(unsigned int x, unsigned int y) : x(x), y(y) {}
+  };
+
+  struct Size {
+    unsigned int width;
+    unsigned int height;
+    Size(unsigned int width, unsigned int height)
+        : width(width), height(height) {}
+  };
+
+  Win32Window();
+  virtual ~Win32Window();
+
+  // Creates a win32 window with |title| that is positioned and sized using
+  // |origin| and |size|. New windows are created on the default monitor. Window
+  // sizes are specified to the OS in physical pixels, hence to ensure a
+  // consistent size this function will scale the inputted width and height as
+  // as appropriate for the default monitor. The window is invisible until
+  // |Show| is called. Returns true if the window was created successfully.
+  bool Create(const std::wstring& title, const Point& origin, const Size& size);
+
+  // Show the current window. Returns true if the window was successfully shown.
+  bool Show();
+
+  // Release OS resources associated with window.
+  void Destroy();
+
+  // Inserts |content| into the window tree.
+  void SetChildContent(HWND content);
+
+  // Returns the backing Window handle to enable clients to set icon and other
+  // window properties. Returns nullptr if the window has been destroyed.
+  HWND GetHandle();
+
+  // If true, closing this window will quit the application.
+  void SetQuitOnClose(bool quit_on_close);
+
+  // Return a RECT representing the bounds of the current client area.
+  RECT GetClientArea();
+
+ protected:
+  // Processes and route salient window messages for mouse handling,
+  // size change and DPI. Delegates handling of these to member overloads that
+  // inheriting classes can handle.
+  virtual LRESULT MessageHandler(HWND window,
+                                 UINT const message,
+                                 WPARAM const wparam,
+                                 LPARAM const lparam) noexcept;
+
+  // Called when CreateAndShow is called, allowing subclass window-related
+  // setup. Subclasses should return false if setup fails.
+  virtual bool OnCreate();
+
+  // Called when Destroy is called.
+  virtual void OnDestroy();
+
+ private:
+  friend class WindowClassRegistrar;
+
+  // OS callback called by message pump. Handles the WM_NCCREATE message which
+  // is passed when the non-client area is being created and enables automatic
+  // non-client DPI scaling so that the non-client area automatically
+  // responds to changes in DPI. All other messages are handled by
+  // MessageHandler.
+  static LRESULT CALLBACK WndProc(HWND const window,
+                                  UINT const message,
+                                  WPARAM const wparam,
+                                  LPARAM const lparam) noexcept;
+
+  // Retrieves a class instance pointer for |window|
+  static Win32Window* GetThisFromHandle(HWND const window) noexcept;
+
+  // Update the window frame's theme to match the system theme.
+  static void UpdateTheme(HWND const window);
+
+  bool quit_on_close_ = false;
+
+  // window handle for top level window.
+  HWND window_handle_ = nullptr;
+
+  // window handle for hosted content.
+  HWND child_content_ = nullptr;
+};
+
+#endif  // RUNNER_WIN32_WINDOW_H_
diff --git a/examples/multiple_windows/.gitignore b/examples/multiple_windows/.gitignore
new file mode 100644
index 0000000..79c113f
--- /dev/null
+++ b/examples/multiple_windows/.gitignore
@@ -0,0 +1,45 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/examples/multiple_windows/.metadata b/examples/multiple_windows/.metadata
new file mode 100644
index 0000000..c9660e9
--- /dev/null
+++ b/examples/multiple_windows/.metadata
@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "f07dbe9f9b40ecc5557632d6feb70a198dab5668"
+  channel: "[user-branch]"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+  platforms:
+    - platform: root
+      create_revision: f07dbe9f9b40ecc5557632d6feb70a198dab5668
+      base_revision: f07dbe9f9b40ecc5557632d6feb70a198dab5668
+    - platform: macos
+      create_revision: f07dbe9f9b40ecc5557632d6feb70a198dab5668
+      base_revision: f07dbe9f9b40ecc5557632d6feb70a198dab5668
+
+  # User provided section
+
+  # List of Local paths (relative to this file) that should be
+  # ignored by the migrate tool.
+  #
+  # Files that are not part of the templates will be ignored by default.
+  unmanaged_files:
+    - 'lib/main.dart'
+    - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/examples/multiple_windows/README.md b/examples/multiple_windows/README.md
new file mode 100644
index 0000000..23c3d31
--- /dev/null
+++ b/examples/multiple_windows/README.md
@@ -0,0 +1,11 @@
+# multiple_windows
+
+A reference application demonstrating multi-window support for Flutter using a
+rich semantics windowing API. At the moment, only the Windows platform is
+supported.
+
+## Running
+To run the example application, you must:
+
+1. Be on Flutter's main release channel
+2. Provide the `--enable-windowing` flag to flutter
diff --git a/examples/multiple_windows/analysis_options.yaml b/examples/multiple_windows/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/examples/multiple_windows/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+  # The lint rules applied to this project can be customized in the
+  # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+  # included above or to enable additional rules. A list of all available lints
+  # and their documentation is published at https://dart.dev/lints.
+  #
+  # Instead of disabling a lint rule for the entire project in the
+  # section below, it can also be suppressed for a single line of code
+  # or a specific dart file by using the `// ignore: name_of_lint` and
+  # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+  # producing the lint.
+  rules:
+    # avoid_print: false  # Uncomment to disable the `avoid_print` rule
+    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/examples/multiple_windows/lib/app/main_window.dart b/examples/multiple_windows/lib/app/main_window.dart
new file mode 100644
index 0000000..c33e1d1
--- /dev/null
+++ b/examples/multiple_windows/lib/app/main_window.dart
@@ -0,0 +1,191 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+// ignore_for_file: implementation_imports
+
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/_window.dart';
+
+import 'regular_window_content.dart';
+import 'window_settings_dialog.dart';
+import 'models.dart';
+import 'regular_window_edit_dialog.dart';
+
+class MainWindow extends StatelessWidget {
+  const MainWindow({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(title: const Text('Multi Window Reference App')),
+      body: Row(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          Expanded(
+            flex: 60,
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.stretch,
+              children: [
+                Expanded(
+                  child: SingleChildScrollView(
+                    scrollDirection: Axis.vertical,
+                    child: _WindowsTable(),
+                  ),
+                ),
+              ],
+            ),
+          ),
+          Expanded(
+            flex: 40,
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.stretch,
+              children: [Expanded(child: _WindowCreatorCard())],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}
+
+class _WindowsTable extends StatelessWidget {
+  List<DataRow> _buildRows(WindowManager windowManager, BuildContext context) {
+    List<DataRow> rows = [];
+    for (KeyedWindow controller in windowManager.windows) {
+      rows.add(
+        DataRow(
+          key: controller.key,
+          color: WidgetStateColor.resolveWith((states) {
+            if (states.contains(WidgetState.selected)) {
+              return Theme.of(context).colorScheme.primary.withAlpha(20);
+            }
+            return Colors.transparent;
+          }),
+          cells: [
+            DataCell(Text('${controller.controller.rootView.viewId}')),
+            DataCell(Text(_getWindowTypeName(controller.controller))),
+            DataCell(
+              Row(
+                children: [
+                  IconButton(
+                    icon: const Icon(Icons.edit_outlined),
+                    onPressed: () => _showWindowEditDialog(controller, context),
+                  ),
+                  IconButton(
+                    icon: const Icon(Icons.delete_outlined),
+                    onPressed: () async {
+                      controller.controller.destroy();
+                    },
+                  ),
+                ],
+              ),
+            ),
+          ],
+        ),
+      );
+    }
+
+    return rows;
+  }
+
+  void _showWindowEditDialog(KeyedWindow controller, BuildContext context) {
+    return switch (controller.controller) {
+      final RegularWindowController regular => showRegularWindowEditDialog(
+        context: context,
+        controller: regular,
+      ),
+    };
+  }
+
+  static String _getWindowTypeName(BaseWindowController controller) {
+    return switch (controller) {
+      RegularWindowController() => 'Regular',
+    };
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final WindowManager windowManager = WindowManagerAccessor.of(context);
+    return DataTable(
+      showBottomBorder: true,
+      columns: const [
+        DataColumn(
+          label: SizedBox(
+            width: 20,
+            child: Text('ID', style: TextStyle(fontSize: 16)),
+          ),
+        ),
+        DataColumn(
+          label: SizedBox(
+            width: 120,
+            child: Text('Type', style: TextStyle(fontSize: 16)),
+          ),
+        ),
+        DataColumn(label: SizedBox(width: 20, child: Text('')), numeric: true),
+      ],
+      rows: _buildRows(windowManager, context),
+    );
+  }
+}
+
+class _WindowCreatorCard extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    final WindowManager windowManager = WindowManagerAccessor.of(context);
+    final WindowSettings windowSettings = WindowSettingsAccessor.of(context);
+    return Card.outlined(
+      margin: const EdgeInsets.symmetric(horizontal: 25),
+      child: Padding(
+        padding: const EdgeInsets.fromLTRB(25, 0, 25, 5),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            const Padding(
+              padding: EdgeInsets.only(top: 10, bottom: 10),
+              child: Text(
+                'New Window',
+                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),
+              ),
+            ),
+            Column(
+              crossAxisAlignment: CrossAxisAlignment.stretch,
+              children: [
+                OutlinedButton(
+                  onPressed: () async {
+                    final UniqueKey key = UniqueKey();
+                    windowManager.add(
+                      KeyedWindow(
+                        key: key,
+                        controller: RegularWindowController(
+                          delegate: CallbackRegularWindowControllerDelegate(
+                            onDestroyed: () => windowManager.remove(key),
+                          ),
+                          title: 'Regular',
+                          preferredSize: windowSettings.regularSize,
+                        ),
+                      ),
+                    );
+                  },
+                  child: const Text('Regular'),
+                ),
+                const SizedBox(height: 8),
+                Container(
+                  alignment: Alignment.bottomRight,
+                  child: TextButton(
+                    child: const Text('SETTINGS'),
+                    onPressed: () {
+                      showWindowSettingsDialog(context, windowSettings);
+                    },
+                  ),
+                ),
+                const SizedBox(width: 8),
+              ],
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/examples/multiple_windows/lib/app/models.dart b/examples/multiple_windows/lib/app/models.dart
new file mode 100644
index 0000000..2465c21
--- /dev/null
+++ b/examples/multiple_windows/lib/app/models.dart
@@ -0,0 +1,93 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+// ignore_for_file: implementation_imports
+
+import 'package:flutter/widgets.dart';
+import 'package:flutter/src/widgets/_window.dart';
+
+class KeyedWindow {
+  KeyedWindow({
+    this.parent,
+    this.isMainWindow = false,
+    required this.key,
+    required this.controller,
+  });
+
+  final BaseWindowController? parent;
+  final bool isMainWindow;
+  final UniqueKey key;
+  final BaseWindowController controller;
+}
+
+/// Provides access to the windows created by the application.
+///
+/// The window manager manages a flat list of all of the [BaseWindowController]s
+/// that have been created by the application as well as which controller is
+/// currently selected by the UI.
+class WindowManager extends ChangeNotifier {
+  WindowManager({required List<KeyedWindow> initialWindows})
+    : _windows = initialWindows;
+
+  final List<KeyedWindow> _windows;
+  List<KeyedWindow> get windows => _windows;
+
+  void add(KeyedWindow window) {
+    _windows.add(window);
+    notifyListeners();
+  }
+
+  void remove(UniqueKey key) {
+    _windows.removeWhere((KeyedWindow window) => window.key == key);
+    notifyListeners();
+  }
+}
+
+/// Provides access to the [WindowManager] from the widget tree.
+class WindowManagerAccessor extends InheritedNotifier<WindowManager> {
+  const WindowManagerAccessor({
+    super.key,
+    required super.child,
+    required WindowManager windowManager,
+  }) : super(notifier: windowManager);
+
+  static WindowManager of(BuildContext context) {
+    final WindowManagerAccessor? result = context
+        .dependOnInheritedWidgetOfExactType<WindowManagerAccessor>();
+    assert(result != null, 'No WindowManager found in context');
+    return result!.notifier!;
+  }
+}
+
+/// Settings that control the behavior of newly created windows.
+class WindowSettings {
+  WindowSettings({this.regularSize = const Size(400, 300)});
+
+  /// The initial size for newly created regular windows.
+  Size regularSize;
+}
+
+/// Provides access to the [WindowSettings] from the widget tree.
+class WindowSettingsAccessor extends InheritedWidget {
+  const WindowSettingsAccessor({
+    super.key,
+    required super.child,
+    required this.windowSettings,
+  });
+
+  final WindowSettings windowSettings;
+
+  static WindowSettings of(BuildContext context) {
+    final WindowSettingsAccessor? result = context
+        .dependOnInheritedWidgetOfExactType<WindowSettingsAccessor>();
+    assert(result != null, 'No WindowSettings found in context');
+    return result!.windowSettings;
+  }
+
+  @override
+  bool updateShouldNotify(WindowSettingsAccessor oldWidget) {
+    return windowSettings != oldWidget.windowSettings;
+  }
+}
diff --git a/examples/multiple_windows/lib/app/regular_window_content.dart b/examples/multiple_windows/lib/app/regular_window_content.dart
new file mode 100644
index 0000000..150c1cc
--- /dev/null
+++ b/examples/multiple_windows/lib/app/regular_window_content.dart
@@ -0,0 +1,122 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+// ignore_for_file: implementation_imports
+
+import 'package:flutter/material.dart';
+import 'window_content.dart';
+import 'models.dart';
+import 'rotated_wire_cube.dart';
+import 'dart:math';
+import 'package:flutter/src/widgets/_window.dart';
+
+class RegularWindowContent extends StatelessWidget {
+  RegularWindowContent({super.key, required this.window})
+    : cubeColor = _generateRandomDarkColor();
+
+  final RegularWindowController window;
+  final Color cubeColor;
+
+  static Color _generateRandomDarkColor() {
+    final random = Random();
+    const int lowerBound = 32;
+    const int span = 160;
+    int red = lowerBound + random.nextInt(span);
+    int green = lowerBound + random.nextInt(span);
+    int blue = lowerBound + random.nextInt(span);
+    return Color.fromARGB(255, red, green, blue);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final dpr = MediaQuery.of(context).devicePixelRatio;
+    final windowSize = WindowScope.contentSizeOf(context);
+    final WindowManager windowManager = WindowManagerAccessor.of(context);
+    final WindowSettings windowSettings = WindowSettingsAccessor.of(context);
+
+    final child = Scaffold(
+      appBar: AppBar(title: Text('Regular Window')),
+      body: Center(
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [RotatedWireCube(cubeColor: cubeColor)],
+            ),
+            Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                ElevatedButton(
+                  onPressed: () {
+                    final UniqueKey key = UniqueKey();
+                    windowManager.add(
+                      KeyedWindow(
+                        key: key,
+                        controller: RegularWindowController(
+                          preferredSize: windowSettings.regularSize,
+                          delegate: CallbackRegularWindowControllerDelegate(
+                            onDestroyed: () => windowManager.remove(key),
+                          ),
+                          title: 'Regular',
+                        ),
+                      ),
+                    );
+                  },
+                  child: const Text('Create Regular Window'),
+                ),
+                const SizedBox(height: 20),
+                Text(
+                  'View #${window.rootView.viewId}\n'
+                  'Size: ${(windowSize.width).toStringAsFixed(1)}\u00D7${(windowSize.height).toStringAsFixed(1)}\n'
+                  'Device Pixel Ratio: $dpr',
+                  textAlign: TextAlign.center,
+                ),
+              ],
+            ),
+          ],
+        ),
+      ),
+    );
+
+    return ViewAnchor(
+      view: ListenableBuilder(
+        listenable: windowManager,
+        builder: (BuildContext context, Widget? child) {
+          final List<Widget> childViews = <Widget>[];
+          for (final KeyedWindow window in windowManager.windows) {
+            if (window.parent == window.controller) {
+              childViews.add(
+                WindowContent(
+                  controller: window.controller,
+                  windowKey: window.key,
+                  onDestroyed: () => windowManager.remove(window.key),
+                  onError: () => windowManager.remove(window.key),
+                ),
+              );
+            }
+          }
+
+          return ViewCollection(views: childViews);
+        },
+      ),
+      child: child,
+    );
+  }
+}
+
+class CallbackRegularWindowControllerDelegate
+    with RegularWindowControllerDelegate {
+  CallbackRegularWindowControllerDelegate({required this.onDestroyed});
+
+  @override
+  void onWindowDestroyed() {
+    onDestroyed();
+    super.onWindowDestroyed();
+  }
+
+  final VoidCallback onDestroyed;
+}
diff --git a/examples/multiple_windows/lib/app/regular_window_edit_dialog.dart b/examples/multiple_windows/lib/app/regular_window_edit_dialog.dart
new file mode 100644
index 0000000..7a5a16f
--- /dev/null
+++ b/examples/multiple_windows/lib/app/regular_window_edit_dialog.dart
@@ -0,0 +1,201 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+// ignore_for_file: implementation_imports
+
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/_window.dart';
+
+void showRegularWindowEditDialog({
+  required BuildContext context,
+  required RegularWindowController controller,
+}) {
+  showDialog(
+    context: context,
+    builder: (context) => _RegularWindowEditDialog(
+      controller: controller,
+      onClose: () => Navigator.pop(context),
+    ),
+  );
+}
+
+class _RegularWindowEditDialog extends StatefulWidget {
+  const _RegularWindowEditDialog({
+    required this.controller,
+    required this.onClose,
+  });
+
+  final RegularWindowController controller;
+  final VoidCallback onClose;
+
+  @override
+  State<StatefulWidget> createState() => _RegularWindowEditDialogState();
+}
+
+class _RegularWindowEditDialogState extends State<_RegularWindowEditDialog> {
+  late Size initialSize;
+  late String initialTitle;
+  late bool initialFullscreen;
+  late bool initialMaximized;
+  late bool initialMinimized;
+
+  late final TextEditingController widthController;
+  late final TextEditingController heightController;
+  late final TextEditingController titleController;
+
+  bool? nextIsFullscreen;
+  bool? nextIsMaximized;
+  bool? nextIsMinized;
+
+  void _init() {
+    widget.controller.addListener(_onNotification);
+    initialSize = widget.controller.contentSize;
+    initialTitle = widget.controller.title;
+    initialFullscreen = widget.controller.isFullscreen;
+    initialMaximized = widget.controller.isMaximized;
+    initialMinimized = widget.controller.isMinimized;
+
+    widthController = TextEditingController(text: initialSize.width.toString());
+    heightController = TextEditingController(
+      text: initialSize.height.toString(),
+    );
+    titleController = TextEditingController(text: initialTitle);
+    nextIsFullscreen = null;
+    nextIsMaximized = null;
+    nextIsMinized = null;
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    _init();
+  }
+
+  @override
+  void didUpdateWidget(covariant _RegularWindowEditDialog oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    if (oldWidget.controller != widget.controller) {
+      oldWidget.controller.removeListener(_onNotification);
+      _init();
+    }
+  }
+
+  void _onNotification() {
+    // We listen on the state of the controller. If a value that the user
+    // can edit changes from what it was initially set to, we invalidate
+    // their current change and store the new "initial" value.
+    if (widget.controller.contentSize != initialSize) {
+      initialSize = widget.controller.contentSize;
+      widthController.text = widget.controller.contentSize.width.toString();
+      heightController.text = widget.controller.contentSize.height.toString();
+    }
+    if (widget.controller.isFullscreen != initialFullscreen) {
+      setState(() {
+        initialFullscreen = widget.controller.isFullscreen;
+        nextIsFullscreen = null;
+      });
+    }
+    if (widget.controller.isMaximized != initialMaximized) {
+      setState(() {
+        initialMaximized = widget.controller.isMaximized;
+        nextIsMaximized = null;
+      });
+    }
+    if (widget.controller.isMinimized != initialMinimized) {
+      setState(() {
+        initialMinimized = widget.controller.isMinimized;
+        nextIsMinized = null;
+      });
+    }
+  }
+
+  @override
+  void dispose() {
+    widget.controller.removeListener(_onNotification);
+    super.dispose();
+  }
+
+  void _onSave() {
+    double? width = double.tryParse(widthController.text);
+    double? height = double.tryParse(heightController.text);
+    String? title = titleController.text.isEmpty ? null : titleController.text;
+    if (width != null &&
+        height != null &&
+        (width != initialSize.width || height != initialSize.height)) {
+      widget.controller.setSize(Size(width, height));
+    }
+    if (title != null && title != initialTitle) {
+      widget.controller.setTitle(title);
+    }
+    if (nextIsFullscreen != null && nextIsFullscreen != initialFullscreen) {
+      widget.controller.setFullscreen(nextIsFullscreen!);
+    }
+    if (nextIsMaximized != null && nextIsMaximized != initialMaximized) {
+      widget.controller.setMaximized(nextIsMaximized!);
+    }
+    if (nextIsMinized != null && nextIsMinized != initialMinimized) {
+      widget.controller.setMinimized(nextIsMinized!);
+    }
+
+    widget.onClose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AlertDialog(
+      title: Text('Edit Window Properties'),
+      content: Column(
+        mainAxisSize: MainAxisSize.min,
+        children: [
+          TextField(
+            controller: widthController,
+            keyboardType: TextInputType.number,
+            decoration: InputDecoration(labelText: 'Width'),
+          ),
+          TextField(
+            controller: heightController,
+            keyboardType: TextInputType.number,
+            decoration: InputDecoration(labelText: 'Height'),
+          ),
+          TextField(
+            controller: titleController,
+            decoration: InputDecoration(labelText: 'Title'),
+          ),
+          CheckboxListTile(
+            title: const Text('Fullscreen'),
+            value: nextIsFullscreen ?? initialFullscreen,
+            onChanged: (bool? value) {
+              if (value != null) {
+                setState(() => nextIsFullscreen = value);
+              }
+            },
+          ),
+          CheckboxListTile(
+            title: const Text('Maximized'),
+            value: nextIsMaximized ?? initialMaximized,
+            onChanged: (bool? value) {
+              if (value != null) {
+                setState(() => nextIsMaximized = value);
+              }
+            },
+          ),
+          CheckboxListTile(
+            title: const Text('Minimized'),
+            value: nextIsMinized ?? initialMinimized,
+            onChanged: (bool? value) {
+              if (value != null) {
+                setState(() => nextIsMinized = value);
+              }
+            },
+          ),
+        ],
+      ),
+      actions: [
+        TextButton(onPressed: () => widget.onClose(), child: Text('Cancel')),
+        TextButton(onPressed: () => _onSave(), child: Text('Save')),
+      ],
+    );
+  }
+}
diff --git a/examples/multiple_windows/lib/app/rotated_wire_cube.dart b/examples/multiple_windows/lib/app/rotated_wire_cube.dart
new file mode 100644
index 0000000..f5e2212
--- /dev/null
+++ b/examples/multiple_windows/lib/app/rotated_wire_cube.dart
@@ -0,0 +1,108 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:vector_math/vector_math_64.dart';
+import 'dart:math';
+
+class RotatedWireCube extends StatefulWidget {
+  const RotatedWireCube({required this.cubeColor, super.key});
+
+  final Color cubeColor;
+
+  @override
+  State<StatefulWidget> createState() => _RotatedWireCubeState();
+}
+
+class _RotatedWireCubeState extends State<RotatedWireCube>
+    with SingleTickerProviderStateMixin {
+  late final AnimationController _animation;
+
+  @override
+  void initState() {
+    super.initState();
+    _animation = AnimationController(
+      vsync: this,
+      lowerBound: 0,
+      upperBound: 2 * pi,
+      duration: const Duration(seconds: 15),
+    )..repeat();
+  }
+
+  @override
+  void dispose() {
+    _animation.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AnimatedBuilder(
+      animation: _animation,
+      builder: (context, child) {
+        return CustomPaint(
+          size: const Size(200, 200),
+          painter: _RotatedWireCubePainter(
+            angle: _animation.value,
+            color: widget.cubeColor,
+          ),
+        );
+      },
+    );
+  }
+}
+
+class _RotatedWireCubePainter extends CustomPainter {
+  static List<Vector3> vertices = [
+    Vector3(-0.5, -0.5, -0.5),
+    Vector3(0.5, -0.5, -0.5),
+    Vector3(0.5, 0.5, -0.5),
+    Vector3(-0.5, 0.5, -0.5),
+    Vector3(-0.5, -0.5, 0.5),
+    Vector3(0.5, -0.5, 0.5),
+    Vector3(0.5, 0.5, 0.5),
+    Vector3(-0.5, 0.5, 0.5),
+  ];
+
+  static const List<List<int>> edges = [
+    [0, 1], [1, 2], [2, 3], [3, 0], // Front face
+    [4, 5], [5, 6], [6, 7], [7, 4], // Back face
+    [0, 4], [1, 5], [2, 6], [3, 7], // Connecting front and back
+  ];
+
+  final double angle;
+  final Color color;
+
+  _RotatedWireCubePainter({required this.angle, required this.color});
+
+  Offset scaleAndCenter(Vector3 point, double size, Offset center) {
+    final scale = size / 2;
+    return Offset(center.dx + point.x * scale, center.dy - point.y * scale);
+  }
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    final rotatedVertices = vertices
+        .map((vertex) => Matrix4.rotationX(angle).transformed3(vertex))
+        .map((vertex) => Matrix4.rotationY(angle).transformed3(vertex))
+        .map((vertex) => Matrix4.rotationZ(angle).transformed3(vertex))
+        .toList();
+
+    final center = Offset(size.width / 2, size.height / 2);
+
+    final paint = Paint()
+      ..color = color
+      ..style = PaintingStyle.stroke
+      ..strokeWidth = 2;
+
+    for (var edge in edges) {
+      final p1 = scaleAndCenter(rotatedVertices[edge[0]], size.width, center);
+      final p2 = scaleAndCenter(rotatedVertices[edge[1]], size.width, center);
+      canvas.drawLine(p1, p2, paint);
+    }
+  }
+
+  @override
+  bool shouldRepaint(_RotatedWireCubePainter oldDelegate) => true;
+}
diff --git a/examples/multiple_windows/lib/app/window_content.dart b/examples/multiple_windows/lib/app/window_content.dart
new file mode 100644
index 0000000..72ea7fd
--- /dev/null
+++ b/examples/multiple_windows/lib/app/window_content.dart
@@ -0,0 +1,38 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+// ignore_for_file: implementation_imports
+
+import 'package:flutter/material.dart';
+import 'regular_window_content.dart';
+import 'package:flutter/src/widgets/_window.dart';
+
+/// Responsible for rendering the appropriate content for a window based on
+/// the type of the window.
+class WindowContent extends StatelessWidget {
+  const WindowContent({
+    required this.windowKey,
+    required this.controller,
+    required this.onDestroyed,
+    required this.onError,
+    super.key,
+  });
+
+  final Key windowKey;
+  final BaseWindowController controller;
+  final VoidCallback onDestroyed;
+  final VoidCallback onError;
+
+  @override
+  Widget build(BuildContext context) {
+    return switch (controller) {
+      final RegularWindowController regular => RegularWindow(
+        key: windowKey,
+        controller: regular,
+        child: MaterialApp(home: RegularWindowContent(window: regular)),
+      ),
+    };
+  }
+}
diff --git a/examples/multiple_windows/lib/app/window_settings_dialog.dart b/examples/multiple_windows/lib/app/window_settings_dialog.dart
new file mode 100644
index 0000000..4e31dfc
--- /dev/null
+++ b/examples/multiple_windows/lib/app/window_settings_dialog.dart
@@ -0,0 +1,94 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'models.dart';
+
+Future<void> showWindowSettingsDialog(
+  BuildContext context,
+  WindowSettings settings,
+) async {
+  return await showDialog(
+    barrierDismissible: true,
+    context: context,
+    builder: (BuildContext ctx) {
+      return _WindowSettingsEditor(
+        settings: settings,
+        onClose: () => Navigator.of(context, rootNavigator: true).pop(),
+      );
+    },
+  );
+}
+
+class _WindowSettingsEditor extends StatefulWidget {
+  const _WindowSettingsEditor({required this.settings, required this.onClose});
+
+  final WindowSettings settings;
+  final void Function() onClose;
+
+  @override
+  State<_WindowSettingsEditor> createState() => _WindowSettingsEditorState();
+}
+
+class _WindowSettingsEditorState extends State<_WindowSettingsEditor> {
+  final TextEditingController _regularWidthController = TextEditingController();
+  final TextEditingController _regularHeightController =
+      TextEditingController();
+
+  @override
+  void initState() {
+    super.initState();
+    _regularWidthController.text = widget.settings.regularSize.width.toString();
+    _regularHeightController.text = widget.settings.regularSize.height
+        .toString();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return SimpleDialog(
+      contentPadding: const EdgeInsets.all(4),
+      titlePadding: const EdgeInsets.fromLTRB(24, 10, 24, 0),
+      title: const Center(child: Text('Window Settings')),
+      children: [
+        ListTile(
+          title: const Text('Regular'),
+          subtitle: Row(
+            children: [
+              Expanded(
+                child: TextFormField(
+                  controller: _regularWidthController,
+                  decoration: const InputDecoration(labelText: 'Initial width'),
+                ),
+              ),
+              const SizedBox(width: 20),
+              Expanded(
+                child: TextFormField(
+                  controller: _regularHeightController,
+                  decoration: const InputDecoration(
+                    labelText: 'Initial height',
+                  ),
+                ),
+              ),
+            ],
+          ),
+        ),
+        Padding(
+          padding: const EdgeInsets.symmetric(horizontal: 16),
+          child: TextButton(
+            onPressed: () {
+              widget.settings.regularSize = Size(
+                double.tryParse(_regularWidthController.text) ??
+                    widget.settings.regularSize.width,
+                double.tryParse(_regularHeightController.text) ??
+                    widget.settings.regularSize.height,
+              );
+              widget.onClose();
+            },
+            child: const Text('Apply'),
+          ),
+        ),
+      ],
+    );
+  }
+}
diff --git a/examples/multiple_windows/lib/main.dart b/examples/multiple_windows/lib/main.dart
new file mode 100644
index 0000000..b8a9d1e
--- /dev/null
+++ b/examples/multiple_windows/lib/main.dart
@@ -0,0 +1,102 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: invalid_use_of_internal_member
+// ignore_for_file: implementation_imports
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'app/models.dart';
+import 'app/window_content.dart';
+import 'app/main_window.dart';
+import 'package:flutter/src/widgets/_window.dart';
+
+class MainControllerWindowDelegate with RegularWindowControllerDelegate {
+  @override
+  void onWindowDestroyed() {
+    super.onWindowDestroyed();
+    exit(0);
+  }
+}
+
+void main() {
+  WidgetsFlutterBinding.ensureInitialized();
+  runWidget(MultiWindowApp());
+}
+
+class MultiWindowApp extends StatefulWidget {
+  const MultiWindowApp({super.key});
+
+  @override
+  State<MultiWindowApp> createState() => _MultiWindowAppState();
+}
+
+class _MultiWindowAppState extends State<MultiWindowApp> {
+  final RegularWindowController controller = RegularWindowController(
+    preferredSize: const Size(800, 600),
+    title: 'Multi-Window Reference Application',
+    delegate: MainControllerWindowDelegate(),
+  );
+  final WindowSettings settings = WindowSettings();
+  late final WindowManager windowManager;
+
+  @override
+  void initState() {
+    super.initState();
+    windowManager = WindowManager(
+      initialWindows: <KeyedWindow>[
+        KeyedWindow(
+          isMainWindow: true,
+          key: UniqueKey(),
+          controller: controller,
+        ),
+      ],
+    );
+  }
+
+  @override
+  void dispose() {
+    controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final Widget mainWindowWidget = RegularWindow(
+      controller: controller,
+      child: MaterialApp(home: MainWindow()),
+    );
+    return WindowManagerAccessor(
+      windowManager: windowManager,
+      child: WindowSettingsAccessor(
+        windowSettings: settings,
+        child: ListenableBuilder(
+          listenable: windowManager,
+          builder: (BuildContext context, Widget? child) {
+            final List<Widget> childViews = <Widget>[mainWindowWidget];
+            for (final KeyedWindow window in windowManager.windows) {
+              // This check renders windows that are not nested below another window as
+              // a child window (e.g. a popup as a child of another window) in addition
+              // to the main window, which is special as it is the one that is currently
+              // being rendered.
+              if (window.parent == null && !window.isMainWindow) {
+                childViews.add(
+                  WindowContent(
+                    controller: window.controller,
+                    windowKey: window.key,
+                    onDestroyed: () => windowManager.remove(window.key),
+                    onError: () => windowManager.remove(window.key),
+                  ),
+                );
+              }
+            }
+
+            return ViewCollection(views: childViews);
+          },
+        ),
+      ),
+    );
+  }
+}
diff --git a/examples/multiple_windows/pubspec.yaml b/examples/multiple_windows/pubspec.yaml
new file mode 100644
index 0000000..2cd9b81
--- /dev/null
+++ b/examples/multiple_windows/pubspec.yaml
@@ -0,0 +1,18 @@
+name: multiple_windows
+
+environment:
+  sdk: ^3.8.0-0
+
+dependencies:
+  flutter:
+    sdk: flutter
+  vector_math: ^2.2.0
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+
+flutter:
+  uses-material-design: true
+
+# PUBSPEC CHECKSUM: lkvhan
diff --git a/examples/multiple_windows/windows/.gitignore b/examples/multiple_windows/windows/.gitignore
new file mode 100644
index 0000000..d492d0d
--- /dev/null
+++ b/examples/multiple_windows/windows/.gitignore
@@ -0,0 +1,17 @@
+flutter/ephemeral/
+
+# Visual Studio user-specific files.
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Visual Studio build-related files.
+x64/
+x86/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
diff --git a/examples/multiple_windows/windows/CMakeLists.txt b/examples/multiple_windows/windows/CMakeLists.txt
new file mode 100644
index 0000000..a3413e9
--- /dev/null
+++ b/examples/multiple_windows/windows/CMakeLists.txt
@@ -0,0 +1,108 @@
+# Project-level configuration.
+cmake_minimum_required(VERSION 3.14)
+project(multiple_windows LANGUAGES CXX)
+
+# The name of the executable created for the application. Change this to change
+# the on-disk name of your application.
+set(BINARY_NAME "multiple_windows")
+
+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
+# versions of CMake.
+cmake_policy(VERSION 3.14...3.25)
+
+# Define build configuration option.
+get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(IS_MULTICONFIG)
+  set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
+    CACHE STRING "" FORCE)
+else()
+  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+    set(CMAKE_BUILD_TYPE "Debug" CACHE
+      STRING "Flutter build mode" FORCE)
+    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+      "Debug" "Profile" "Release")
+  endif()
+endif()
+# Define settings for the Profile build mode.
+set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
+set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
+set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
+set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
+
+# Use Unicode for all projects.
+add_definitions(-DUNICODE -D_UNICODE)
+
+# Compilation settings that should be applied to most targets.
+#
+# Be cautious about adding new options here, as plugins use this function by
+# default. In most cases, you should add new options to specific targets instead
+# of modifying this function.
+function(APPLY_STANDARD_SETTINGS TARGET)
+  target_compile_features(${TARGET} PUBLIC cxx_std_17)
+  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
+  target_compile_options(${TARGET} PRIVATE /EHsc)
+  target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
+  target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
+endfunction()
+
+# Flutter library and tool build rules.
+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
+add_subdirectory(${FLUTTER_MANAGED_DIR})
+
+# Application build; see runner/CMakeLists.txt.
+add_subdirectory("runner")
+
+
+# Generated plugin build rules, which manage building the plugins and adding
+# them to the application.
+include(flutter/generated_plugins.cmake)
+
+
+# === Installation ===
+# Support files are copied into place next to the executable, so that it can
+# run in place. This is done instead of making a separate bundle (as on Linux)
+# so that building and running from within Visual Studio will work.
+set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
+# Make the "install" step default, as it's required to run.
+set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
+endif()
+
+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
+
+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+  COMPONENT Runtime)
+
+if(PLUGIN_BUNDLED_LIBRARIES)
+  install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
+    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+    COMPONENT Runtime)
+endif()
+
+# Copy the native assets provided by the build.dart from all packages.
+set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
+install(DIRECTORY "${NATIVE_ASSETS_DIR}"
+   DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+   COMPONENT Runtime)
+
+# Fully re-copy the assets directory on each build to avoid having stale files
+# from a previous install.
+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
+install(CODE "
+  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
+  " COMPONENT Runtime)
+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
+  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
+
+# Install the AOT library on non-Debug builds only.
+install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  CONFIGURATIONS Profile;Release
+  COMPONENT Runtime)
diff --git a/examples/multiple_windows/windows/flutter/CMakeLists.txt b/examples/multiple_windows/windows/flutter/CMakeLists.txt
new file mode 100644
index 0000000..a71c6e2
--- /dev/null
+++ b/examples/multiple_windows/windows/flutter/CMakeLists.txt
@@ -0,0 +1,109 @@
+# This file controls Flutter-level build steps. It should not be edited.
+cmake_minimum_required(VERSION 3.14)
+
+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
+set(CMAKE_CXX_STANDARD 20)
+
+# Configuration provided via flutter tool.
+include(${EPHEMERAL_DIR}/generated_config.cmake)
+
+# TODO: Move the rest of this into files in ephemeral. See
+# https://github.com/flutter/flutter/issues/57146.
+set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
+
+# Set fallback configurations for older versions of the flutter tool.
+if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
+  set(FLUTTER_TARGET_PLATFORM "windows-x64")
+endif()
+
+# === Flutter Library ===
+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
+
+# Published to parent scope for install step.
+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
+set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
+
+list(APPEND FLUTTER_LIBRARY_HEADERS
+  "flutter_export.h"
+  "flutter_windows.h"
+  "flutter_messenger.h"
+  "flutter_plugin_registrar.h"
+  "flutter_texture_registrar.h"
+)
+list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
+add_library(flutter INTERFACE)
+target_include_directories(flutter INTERFACE
+  "${EPHEMERAL_DIR}"
+)
+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
+add_dependencies(flutter flutter_assemble)
+
+# === Wrapper ===
+list(APPEND CPP_WRAPPER_SOURCES_CORE
+  "core_implementations.cc"
+  "standard_codec.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
+  "plugin_registrar.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_APP
+  "flutter_engine.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
+
+# Wrapper sources needed for a plugin.
+add_library(flutter_wrapper_plugin STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+)
+apply_standard_settings(flutter_wrapper_plugin)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  POSITION_INDEPENDENT_CODE ON)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  CXX_VISIBILITY_PRESET hidden)
+target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
+target_include_directories(flutter_wrapper_plugin PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_plugin flutter_assemble)
+
+# Wrapper sources needed for the runner.
+add_library(flutter_wrapper_app STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
+apply_standard_settings(flutter_wrapper_app)
+target_link_libraries(flutter_wrapper_app PUBLIC flutter)
+target_include_directories(flutter_wrapper_app PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_app flutter_assemble)
+
+# === Flutter tool backend ===
+# _phony_ is a non-existent file to force this command to run every time,
+# since currently there's no way to get a full input/output list from the
+# flutter tool.
+set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
+set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
+add_custom_command(
+  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
+    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
+    ${CPP_WRAPPER_SOURCES_APP}
+    ${PHONY_OUTPUT}
+  COMMAND ${CMAKE_COMMAND} -E env
+    ${FLUTTER_TOOL_ENVIRONMENT}
+    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
+      ${FLUTTER_TARGET_PLATFORM} $<CONFIG>
+  VERBATIM
+)
+add_custom_target(flutter_assemble DEPENDS
+  "${FLUTTER_LIBRARY}"
+  ${FLUTTER_LIBRARY_HEADERS}
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
diff --git a/examples/multiple_windows/windows/runner/CMakeLists.txt b/examples/multiple_windows/windows/runner/CMakeLists.txt
new file mode 100644
index 0000000..697f434
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.14)
+project(runner LANGUAGES CXX)
+
+# Define the application target. To change its name, change BINARY_NAME in the
+# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
+# work.
+#
+# Any new source files that you add to the application should be added here.
+add_executable(${BINARY_NAME} WIN32
+  "main.cpp"
+  "utils.cpp"
+  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
+  "Runner.rc"
+  "runner.exe.manifest"
+)
+
+# Apply the standard set of build settings. This can be removed for applications
+# that need different build settings.
+apply_standard_settings(${BINARY_NAME})
+
+# Add preprocessor definitions for the build version.
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
+
+# Disable Windows macros that collide with C++ standard library functions.
+target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
+
+# Add dependency libraries and include directories. Add any application-specific
+# dependencies here.
+target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
+target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+
+# Run the Flutter tool portions of the build. This must not be removed.
+add_dependencies(${BINARY_NAME} flutter_assemble)
diff --git a/examples/multiple_windows/windows/runner/Runner.rc b/examples/multiple_windows/windows/runner/Runner.rc
new file mode 100644
index 0000000..d9d3832
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/Runner.rc
@@ -0,0 +1,111 @@
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#include ""winres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
+#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
+#else
+#define VERSION_AS_NUMBER 1,0,0,0
+#endif
+
+#if defined(FLUTTER_VERSION)
+#define VERSION_AS_STRING FLUTTER_VERSION
+#else
+#define VERSION_AS_STRING "1.0.0"
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_AS_NUMBER
+ PRODUCTVERSION VERSION_AS_NUMBER
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "The Flutter Authors" "\0"
+            VALUE "FileDescription", "A reference application demonstrating Flutter's multi-window API." "\0"
+            VALUE "FileVersion", VERSION_AS_STRING "\0"
+            VALUE "InternalName", "Flutter Multi-Window Reference App" "\0"
+            VALUE "LegalCopyright", "Copyright 2014 The Flutter Authors. All rights reserved." "\0"
+            VALUE "OriginalFilename", "multiple_windows.exe" "\0"
+            VALUE "ProductName", "Flutter Multi-Window Reference App" "\0"
+            VALUE "ProductVersion", VERSION_AS_STRING "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/examples/multiple_windows/windows/runner/main.cpp b/examples/multiple_windows/windows/runner/main.cpp
new file mode 100644
index 0000000..11a76c8
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/main.cpp
@@ -0,0 +1,41 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <flutter/dart_project.h>
+#include <flutter/flutter_engine.h>
+#include <flutter/generated_plugin_registrant.h>
+
+#include "utils.h"
+
+int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
+                      _In_ wchar_t* command_line, _In_ int show_command) {
+  // Attach to console when present (e.g., 'flutter run') or create a
+  // new console when running with a debugger.
+  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
+    CreateAndAttachConsole();
+  }
+
+  // Initialize COM, so that it is available for use in the library and/or
+  // plugins.
+  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+
+  flutter::DartProject project(L"data");
+
+  auto command_line_arguments{GetCommandLineArguments()};
+
+  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
+
+  auto const engine{std::make_shared<flutter::FlutterEngine>(project)};
+  RegisterPlugins(engine.get());
+  engine->Run();
+
+  ::MSG msg;
+  while (::GetMessage(&msg, nullptr, 0, 0)) {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+  }
+
+  ::CoUninitialize();
+  return EXIT_SUCCESS;
+}
diff --git a/examples/multiple_windows/windows/runner/resource.h b/examples/multiple_windows/windows/runner/resource.h
new file mode 100644
index 0000000..69cacf3
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/resource.h
@@ -0,0 +1,19 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Runner.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        102
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/examples/multiple_windows/windows/runner/runner.exe.manifest b/examples/multiple_windows/windows/runner/runner.exe.manifest
new file mode 100644
index 0000000..153653e
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/runner.exe.manifest
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
+    </windowsSettings>
+  </application>
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- Windows 10 and Windows 11 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+    </application>
+  </compatibility>
+</assembly>
diff --git a/examples/multiple_windows/windows/runner/utils.cpp b/examples/multiple_windows/windows/runner/utils.cpp
new file mode 100644
index 0000000..6abcd65
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/utils.cpp
@@ -0,0 +1,68 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "utils.h"
+
+#include <flutter_windows.h>
+#include <io.h>
+#include <stdio.h>
+#include <windows.h>
+
+#include <iostream>
+
+void CreateAndAttachConsole() {
+  if (::AllocConsole()) {
+    FILE *unused;
+    if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
+      _dup2(_fileno(stdout), 1);
+    }
+    if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
+      _dup2(_fileno(stdout), 2);
+    }
+    std::ios::sync_with_stdio();
+    FlutterDesktopResyncOutputStreams();
+  }
+}
+
+std::vector<std::string> GetCommandLineArguments() {
+  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
+  int argc;
+  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
+  if (argv == nullptr) {
+    return std::vector<std::string>();
+  }
+
+  std::vector<std::string> command_line_arguments;
+
+  // Skip the first argument as it's the binary name.
+  for (int i = 1; i < argc; i++) {
+    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
+  }
+
+  ::LocalFree(argv);
+
+  return command_line_arguments;
+}
+
+std::string Utf8FromUtf16(const wchar_t* utf16_string) {
+  if (utf16_string == nullptr) {
+    return std::string();
+  }
+  unsigned int target_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      -1, nullptr, 0, nullptr, nullptr)
+    -1; // remove the trailing null character
+  std::string utf8_string;
+  if (target_length == 0 || target_length > utf8_string.max_size()) {
+    return utf8_string;
+  }
+  utf8_string.resize(target_length);
+  int converted_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      -1, utf8_string.data(), target_length, nullptr, nullptr);
+  if (converted_length == 0) {
+    return std::string();
+  }
+  return utf8_string;
+}
diff --git a/examples/multiple_windows/windows/runner/utils.h b/examples/multiple_windows/windows/runner/utils.h
new file mode 100644
index 0000000..54414c9
--- /dev/null
+++ b/examples/multiple_windows/windows/runner/utils.h
@@ -0,0 +1,23 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef RUNNER_UTILS_H_
+#define RUNNER_UTILS_H_
+
+#include <string>
+#include <vector>
+
+// Creates a console for the process, and redirects stdout and stderr to
+// it for both the runner and the Flutter library.
+void CreateAndAttachConsole();
+
+// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
+// encoded in UTF-8. Returns an empty std::string on failure.
+std::string Utf8FromUtf16(const wchar_t* utf16_string);
+
+// Gets the command line arguments passed in as a std::vector<std::string>,
+// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
+std::vector<std::string> GetCommandLineArguments();
+
+#endif  // RUNNER_UTILS_H_
diff --git a/packages/flutter/lib/src/foundation/_features.dart b/packages/flutter/lib/src/foundation/_features.dart
index 283d43b..f9a6aca 100644
--- a/packages/flutter/lib/src/foundation/_features.dart
+++ b/packages/flutter/lib/src/foundation/_features.dart
@@ -14,6 +14,9 @@
 /// files will throw an `UnsupportedError`:
 ///
 /// 1. packages/flutter/lib/src/widgets/_window.dart
+/// 2. packages/flutter/lib/src/widgets/_window_io.dart
+/// 3. packages/flutter/lib/src/widgets/_window_web.dart
+/// 4. packages/flutter/lib/src/widgets/_window_win32.dart
 ///
 /// See: https://github.com/flutter/flutter/issues/30701.
 @internal
@@ -23,6 +26,6 @@
 ///
 /// Do not use this API. Flutter can and will make breaking changes to this API.
 @internal
-Set<String> debugEnabledFeatureFlags = <String>{
+final Set<String> debugEnabledFeatureFlags = <String>{
   ...const String.fromEnvironment('FLUTTER_ENABLED_FEATURE_FLAGS').split(','),
 };
diff --git a/packages/flutter/lib/src/widgets/_window.dart b/packages/flutter/lib/src/widgets/_window.dart
index 9aa703a..5540b8e 100644
--- a/packages/flutter/lib/src/widgets/_window.dart
+++ b/packages/flutter/lib/src/widgets/_window.dart
@@ -10,19 +10,21 @@
 //
 // 1. Have the `@internal` attribute.
 // 2. Throw an `UnsupportedError` if `isWindowingEnabled`
-//    is `false.
+//    is `false`.
 //
 // See: https://github.com/flutter/flutter/issues/30701.
 
 import 'dart:ui' show Display, FlutterView;
 
 import 'package:flutter/foundation.dart';
-import 'package:flutter/rendering.dart';
 
 import '../foundation/_features.dart';
+import '_window_io.dart' if (dart.library.js_interop) '_window_web.dart' as window_impl;
+import 'basic.dart';
 import 'binding.dart';
 import 'framework.dart';
 import 'inherited_model.dart';
+import 'transitions.dart';
 import 'view.dart';
 
 const String _kWindowingDisabledErrorMessage = '''
@@ -60,7 +62,7 @@
 ///
 ///  * [RegularWindowController], the controller for regular top-level windows.
 @internal
-sealed class BaseWindowController {
+sealed class BaseWindowController extends ChangeNotifier {
   /// The current size of the drawable area of the window.
   ///
   /// This might differ from the requested size.
@@ -137,12 +139,6 @@
     if (!isWindowingEnabled) {
       throw UnsupportedError(_kWindowingDisabledErrorMessage);
     }
-
-    final WindowingOwner owner = WidgetsBinding.instance.windowingOwner;
-    if (!owner.hasTopLevelWindows()) {
-      // TODO(mattkae): close the application if this is the last window
-      // via ServicesBinding.instance.exitApplication(AppExitType.cancelable);
-    }
   }
 }
 
@@ -246,12 +242,18 @@
     );
   }
 
-  /// Creates an empty [RegularWindowController] for testing purposes.
+  /// Creates an empty [RegularWindowController].
+  ///
+  /// This method is only intended to be used by subclasses of the
+  /// [RegularWindowController].
+  ///
+  /// Users who want to instantiate a new [RegularWindowController] should
+  /// always use the factory method to create a controller that is valid
+  /// for their particular platform.
   ///
   /// {@macro flutter.widgets.windowing.experimental}
   @internal
   @protected
-  @visibleForTesting
   RegularWindowController.empty();
 
   /// The current title of the window.
@@ -398,19 +400,23 @@
   /// {@macro flutter.widgets.windowing.experimental}
   @internal
   bool hasTopLevelWindows();
+}
 
-  /// Creates default windowing owner for standard desktop embedders.
-  ///
-  /// {@macro flutter.widgets.windowing.experimental}
-  @internal
-  static WindowingOwner createDefaultOwner() {
-    if (!isWindowingEnabled) {
-      return _WindowingOwnerUnsupported(errorMessage: _kWindowingDisabledErrorMessage);
-    }
-
-    // TODO(mattkae): Implement windowing owners for desktop platforms.
-    return _WindowingOwnerUnsupported(errorMessage: 'Windowing is unsupported on this platform.');
+/// Creates default windowing owner for standard desktop embedders.
+///
+/// {@macro flutter.widgets.windowing.experimental}
+@internal
+WindowingOwner createDefaultWindowingOwner() {
+  if (!isWindowingEnabled) {
+    return _WindowingOwnerUnsupported(errorMessage: _kWindowingDisabledErrorMessage);
   }
+
+  final WindowingOwner? owner = window_impl.createDefaultOwner();
+  if (owner != null) {
+    return owner;
+  }
+
+  return _WindowingOwnerUnsupported(errorMessage: 'Windowing is unsupported on this platform.');
 }
 
 /// Windowing delegate used on platforms that do not support windowing.
@@ -507,9 +513,12 @@
   @internal
   @override
   Widget build(BuildContext context) {
-    return WindowScope(
-      controller: controller,
-      child: View(view: controller.rootView, child: child),
+    return ListenableBuilder(
+      listenable: controller,
+      builder: (BuildContext context, Widget? widget) => WindowScope(
+        controller: controller,
+        child: View(view: controller.rootView, child: child),
+      ),
     );
   }
 }
diff --git a/packages/flutter/lib/src/widgets/_window_io.dart b/packages/flutter/lib/src/widgets/_window_io.dart
new file mode 100644
index 0000000..071a58b
--- /dev/null
+++ b/packages/flutter/lib/src/widgets/_window_io.dart
@@ -0,0 +1,37 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Do not import this file in production applications or packages published
+// to pub.dev. Flutter will make breaking changes to this file, even in patch
+// versions.
+//
+// All APIs in this file must be private or must:
+//
+// 1. Have the `@internal` attribute.
+// 2. Throw an `UnsupportedError` if `isWindowingEnabled`
+//    is `false`.
+//
+// See: https://github.com/flutter/flutter/issues/30701.
+
+import 'dart:io';
+
+import 'package:flutter/foundation.dart';
+
+import '_window.dart';
+import '_window_win32.dart';
+
+/// Creates a default [WindowingOwner] for the current platform.
+///
+/// Returns null if windowing is not supported on the current platform.
+/// Only supported on desktop platforms.
+///
+/// {@macro flutter.widgets.windowing.experimental}
+@internal
+WindowingOwner? createDefaultOwner() {
+  if (Platform.isWindows) {
+    return WindowingOwnerWin32();
+  } else {
+    return null;
+  }
+}
diff --git a/packages/flutter/lib/src/widgets/_window_web.dart b/packages/flutter/lib/src/widgets/_window_web.dart
new file mode 100644
index 0000000..da3ddc7
--- /dev/null
+++ b/packages/flutter/lib/src/widgets/_window_web.dart
@@ -0,0 +1,29 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Do not import this file in production applications or packages published
+// to pub.dev. Flutter will make breaking changes to this file, even in patch
+// versions.
+//
+// All APIs in this file must be private or must:
+//
+// 1. Have the `@internal` attribute.
+// 2. Throw an `UnsupportedError` if `isWindowingEnabled`
+//    is `false`.
+//
+// See: https://github.com/flutter/flutter/issues/30701.
+
+import 'package:flutter/foundation.dart';
+
+import '_window.dart';
+
+/// Creates a default [WindowingOwner] for web.
+///
+/// Returns `null` as web does not support multiple windows.
+///
+/// {@macro flutter.widgets.windowing.experimental}
+@internal
+WindowingOwner? createDefaultOwner() {
+  return null;
+}
diff --git a/packages/flutter/lib/src/widgets/_window_win32.dart b/packages/flutter/lib/src/widgets/_window_win32.dart
new file mode 100644
index 0000000..1d6a81c
--- /dev/null
+++ b/packages/flutter/lib/src/widgets/_window_win32.dart
@@ -0,0 +1,856 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Do not import this file in production applications or packages published
+// to pub.dev. Flutter will make breaking changes to this file, even in patch
+// versions.
+//
+// All APIs in this file must be private or must:
+//
+// 1. Have the `@internal` attribute.
+// 2. Throw an `UnsupportedError` if `isWindowingEnabled`
+//    is `false`.
+//
+// See: https://github.com/flutter/flutter/issues/30701.
+
+import 'dart:ffi' as ffi;
+import 'dart:io';
+import 'dart:typed_data';
+import 'dart:ui' show Display, FlutterView;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/rendering.dart';
+
+import '../foundation/_features.dart';
+import '_window.dart';
+
+/// A Win32 window handle.
+///
+/// {@macro flutter.widgets.windowing.experimental}
+@internal
+typedef HWND = ffi.Pointer<ffi.Void>;
+
+const int _WM_SIZE = 0x0005;
+const int _WM_ACTIVATE = 0x0006;
+const int _WM_CLOSE = 0x0010;
+
+const int _SW_RESTORE = 9;
+const int _SW_MAXIMIZE = 3;
+const int _SW_MINIMIZE = 6;
+
+const String _kWindowingDisabledErrorMessage = '''
+Windowing APIs are not enabled.
+
+Windowing APIs are currently experimental. Do not use windowing APIs in
+production applications or plugins published to pub.dev.
+
+To try experimental windowing APIs:
+1. Switch to Flutter's main release channel.
+2. Turn on the windowing feature flag.
+
+See: https://github.com/flutter/flutter/issues/30701.
+''';
+
+/// Abstract handler class for Windows messages.
+///
+/// Implementations of this class should register with
+/// [WindowingOwnerWin32.addMessageHandler] to begin receiving messages.
+/// When finished handling messages, implementations should deregister
+/// themselves with [WindowingOwnerWin32.removeMessageHandler].
+abstract class _WindowsMessageHandler {
+  /// Handles a window message.
+  ///
+  /// Returned value, if not null will be returned to the system as LRESULT
+  /// and will stop all other handlers from being called. See
+  /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
+  /// for more information.
+  ///
+  /// {@macro flutter.widgets.windowing.experimental}
+  @internal
+  int? handleWindowsMessage(
+    FlutterView view,
+    HWND windowHandle,
+    int message,
+    int wParam,
+    int lParam,
+  );
+}
+
+/// [WindowingOwner] implementation for Windows.
+///
+/// If [Platform.isWindows] is false, then the constructor will throw an
+/// [UnsupportedError].
+///
+/// {@macro flutter.widgets.windowing.experimental}
+///
+/// See also:
+///
+///  * [WindowingOwner], the abstract class that manages native windows.
+@internal
+class WindowingOwnerWin32 extends WindowingOwner {
+  /// Creates a new [WindowingOwnerWin32] instance.
+  ///
+  /// If [Platform.isWindows] is false, then this constructor will throw an
+  /// [UnsupportedError]
+  ///
+  ///
+  /// {@macro flutter.widgets.windowing.experimental}
+  ///
+  /// See also:
+  ///
+  ///  * [WindowingOwner], the abstract class that manages native windows.
+  @internal
+  WindowingOwnerWin32() : allocator = _CallocAllocator() {
+    if (!isWindowingEnabled) {
+      throw UnsupportedError(_kWindowingDisabledErrorMessage);
+    }
+
+    if (!Platform.isWindows) {
+      throw UnsupportedError('Only available on the Win32 platform');
+    }
+
+    assert(
+      PlatformDispatcher.instance.engineId != null,
+      'WindowingOwnerWin32 must be created after the engine has been initialized.',
+    );
+
+    _Win32PlatformInterface.initializeWindowing(
+      allocator,
+      PlatformDispatcher.instance.engineId!,
+      _onMessage,
+    );
+  }
+
+  final List<_WindowsMessageHandler> _messageHandlers = <_WindowsMessageHandler>[];
+
+  /// The [Allocator] used for allocating native memory in this owner.
+  ///
+  /// This can be overridden via the [WindowingOwnerWin32.test] constructor.
+  ///
+  /// {@macro flutter.widgets.windowing.experimental}
+  @internal
+  final ffi.Allocator allocator;
+
+  @internal
+  @override
+  RegularWindowController createRegularWindowController({
+    Size? preferredSize,
+    BoxConstraints? preferredConstraints,
+    String? title,
+    required RegularWindowControllerDelegate delegate,
+  }) {
+    return RegularWindowControllerWin32(
+      owner: this,
+      delegate: delegate,
+      preferredSize: preferredSize,
+      preferredConstraints: preferredConstraints,
+      title: title,
+    );
+  }
+
+  /// Register a new [WindowsMessageHandler].
+  ///
+  /// The handler will be triggered for unhandled messages for all top level
+  /// windows.
+  ///
+  /// Adding a handler multiple times has no effect.
+  ///
+  /// Handlers are called in the order that they are added.
+  ///
+  /// Callers must remove their message handlers using
+  /// [WindowingOwnerWin32._removeMessageHandler].
+  void _addMessageHandler(_WindowsMessageHandler handler) {
+    if (_messageHandlers.contains(handler)) {
+      return;
+    }
+
+    _messageHandlers.add(handler);
+  }
+
+  /// Unregister a [WindowsMessageHandler].
+  ///
+  /// If the handler has not been registered, this method has no effect.
+  void _removeMessageHandler(_WindowsMessageHandler handler) {
+    _messageHandlers.remove(handler);
+  }
+
+  void _onMessage(ffi.Pointer<_WindowsMessage> message) {
+    final FlutterView flutterView = PlatformDispatcher.instance.views.firstWhere(
+      (FlutterView view) => view.viewId == message.ref.viewId,
+    );
+
+    final int handlesLength = _messageHandlers.length;
+    for (final _WindowsMessageHandler handler in _messageHandlers) {
+      assert(
+        _messageHandlers.length == handlesLength,
+        'Message handler list changed while processing message: $message',
+      );
+      final int? result = handler.handleWindowsMessage(
+        flutterView,
+        message.ref.windowHandle,
+        message.ref.message,
+        message.ref.wParam,
+        message.ref.lParam,
+      );
+      if (result != null) {
+        message.ref.handled = true;
+        message.ref.lResult = result;
+        return;
+      }
+    }
+  }
+
+  @internal
+  @override
+  bool hasTopLevelWindows() {
+    return _Win32PlatformInterface.hasTopLevelWindows(PlatformDispatcher.instance.engineId!);
+  }
+}
+
+class _RegularWindowMesageHandler implements _WindowsMessageHandler {
+  _RegularWindowMesageHandler({required this.controller});
+
+  final RegularWindowControllerWin32 controller;
+
+  @override
+  int? handleWindowsMessage(
+    FlutterView view,
+    HWND windowHandle,
+    int message,
+    int wParam,
+    int lParam,
+  ) {
+    return controller._handleWindowsMessage(view, windowHandle, message, wParam, lParam);
+  }
+}
+
+/// Implementation of [RegularWindowController] for the Windows platform.
+///
+/// {@macro flutter.widgets.windowing.experimental}
+///
+/// See also:
+///
+///  * [RegularWindowController], the base class for regular windows.
+class RegularWindowControllerWin32 extends RegularWindowController {
+  /// Creates a new regular window controller for Win32.
+  ///
+  /// When this constructor completes the native window has been created and
+  /// has a view associated with it.
+  ///
+  /// {@macro flutter.widgets.windowing.experimental}
+  ///
+  /// See also:
+  ///
+  ///  * [RegularWindowController], the base class for regular windows.
+  @internal
+  RegularWindowControllerWin32({
+    required WindowingOwnerWin32 owner,
+    required RegularWindowControllerDelegate delegate,
+    Size? preferredSize,
+    BoxConstraints? preferredConstraints,
+    String? title,
+  }) : _owner = owner,
+       _delegate = delegate,
+       super.empty() {
+    if (!isWindowingEnabled) {
+      throw UnsupportedError(_kWindowingDisabledErrorMessage);
+    }
+
+    _handler = _RegularWindowMesageHandler(controller: this);
+    owner._addMessageHandler(_handler);
+    final int viewId = _Win32PlatformInterface.createWindow(
+      _owner.allocator,
+      PlatformDispatcher.instance.engineId!,
+      preferredSize,
+      preferredConstraints,
+      title,
+    );
+    final FlutterView flutterView = PlatformDispatcher.instance.views.firstWhere(
+      (FlutterView view) => view.viewId == viewId,
+    );
+    rootView = flutterView;
+  }
+
+  final WindowingOwnerWin32 _owner;
+  final RegularWindowControllerDelegate _delegate;
+  late final _RegularWindowMesageHandler _handler;
+  bool _destroyed = false;
+
+  @override
+  @internal
+  Size get contentSize {
+    _ensureNotDestroyed();
+    final _ActualContentSize size = _Win32PlatformInterface.getWindowContentSize(getWindowHandle());
+    final Size result = Size(size.width, size.height);
+    return result;
+  }
+
+  @override
+  @internal
+  String get title {
+    _ensureNotDestroyed();
+    return _Win32PlatformInterface.getWindowTitle(_owner.allocator, getWindowHandle());
+  }
+
+  @override
+  @internal
+  bool get isActivated {
+    _ensureNotDestroyed();
+    return _Win32PlatformInterface.getForegroundWindow() == getWindowHandle();
+  }
+
+  @override
+  @internal
+  bool get isMaximized {
+    _ensureNotDestroyed();
+    return _Win32PlatformInterface.isZoomed(getWindowHandle()) != 0;
+  }
+
+  @override
+  @internal
+  bool get isMinimized {
+    _ensureNotDestroyed();
+    return _Win32PlatformInterface.isIconic(getWindowHandle()) != 0;
+  }
+
+  @override
+  @internal
+  bool get isFullscreen {
+    _ensureNotDestroyed();
+    return _Win32PlatformInterface.getFullscreen(getWindowHandle());
+  }
+
+  @override
+  @internal
+  void setSize(Size? size) {
+    _ensureNotDestroyed();
+    _Win32PlatformInterface.setWindowContentSize(_owner.allocator, getWindowHandle(), size);
+  }
+
+  @override
+  @internal
+  void setConstraints(BoxConstraints constraints) {
+    _ensureNotDestroyed();
+    _Win32PlatformInterface.setWindowConstraints(_owner.allocator, getWindowHandle(), constraints);
+    notifyListeners();
+  }
+
+  @override
+  @internal
+  void setTitle(String title) {
+    _ensureNotDestroyed();
+    _Win32PlatformInterface.setWindowTitle(_owner.allocator, getWindowHandle(), title);
+    notifyListeners();
+  }
+
+  @override
+  @internal
+  void activate() {
+    _ensureNotDestroyed();
+    _Win32PlatformInterface.showWindow(getWindowHandle(), _SW_RESTORE);
+  }
+
+  @override
+  @internal
+  void setMaximized(bool maximized) {
+    _ensureNotDestroyed();
+    if (maximized) {
+      _Win32PlatformInterface.showWindow(getWindowHandle(), _SW_MAXIMIZE);
+    } else {
+      _Win32PlatformInterface.showWindow(getWindowHandle(), _SW_RESTORE);
+    }
+  }
+
+  @override
+  @internal
+  void setMinimized(bool minimized) {
+    _ensureNotDestroyed();
+    if (minimized) {
+      _Win32PlatformInterface.showWindow(getWindowHandle(), _SW_MINIMIZE);
+    } else {
+      _Win32PlatformInterface.showWindow(getWindowHandle(), _SW_RESTORE);
+    }
+  }
+
+  @override
+  @internal
+  void setFullscreen(bool fullscreen, {Display? display}) {
+    _Win32PlatformInterface.setFullscreen(
+      _owner.allocator,
+      getWindowHandle(),
+      fullscreen,
+      display: display,
+    );
+  }
+
+  /// Returns HWND pointer to the top level window.
+  @internal
+  HWND getWindowHandle() {
+    _ensureNotDestroyed();
+    return _Win32PlatformInterface.getWindowHandle(
+      PlatformDispatcher.instance.engineId!,
+      rootView.viewId,
+    );
+  }
+
+  void _ensureNotDestroyed() {
+    if (_destroyed) {
+      throw StateError('Window has been destroyed.');
+    }
+  }
+
+  @override
+  void destroy() {
+    if (_destroyed) {
+      return;
+    }
+    _Win32PlatformInterface.destroyWindow(getWindowHandle());
+    _destroyed = true;
+    _owner._removeMessageHandler(_handler);
+    _delegate.onWindowDestroyed();
+  }
+
+  int? _handleWindowsMessage(
+    FlutterView view,
+    HWND windowHandle,
+    int message,
+    int wParam,
+    int lParam,
+  ) {
+    if (view.viewId != rootView.viewId) {
+      return null;
+    }
+
+    if (message == _WM_CLOSE) {
+      _delegate.onWindowCloseRequested(this);
+      return 0;
+    } else if (message == _WM_SIZE || message == _WM_ACTIVATE) {
+      notifyListeners();
+    }
+    return null;
+  }
+}
+
+class _Win32PlatformInterface {
+  @ffi.Native<ffi.Bool Function(ffi.Int64)>(
+    symbol: 'InternalFlutterWindows_WindowManager_HasTopLevelWindows',
+  )
+  external static bool hasTopLevelWindows(int engineId);
+
+  static void initializeWindowing(
+    ffi.Allocator allocator,
+    int engineId,
+    void Function(ffi.Pointer<_WindowsMessage>) onMessage,
+  ) {
+    final ffi.Pointer<_WindowingInitRequest> request = allocator<_WindowingInitRequest>();
+    try {
+      request.ref.onMessage =
+          ffi.NativeCallable<ffi.Void Function(ffi.Pointer<_WindowsMessage>)>.isolateLocal(
+            onMessage,
+          ).nativeFunction;
+      _initializeWindowing(engineId, request);
+    } finally {
+      allocator.free(request);
+    }
+  }
+
+  @ffi.Native<ffi.Void Function(ffi.Int64, ffi.Pointer<_WindowingInitRequest>)>(
+    symbol: 'InternalFlutterWindows_WindowManager_Initialize',
+  )
+  external static void _initializeWindowing(
+    int engineId,
+    ffi.Pointer<_WindowingInitRequest> request,
+  );
+
+  static int createWindow(
+    ffi.Allocator allocator,
+    int engineId,
+    Size? preferredSize,
+    BoxConstraints? preferredConstraints,
+    String? title,
+  ) {
+    final ffi.Pointer<_WindowCreationRequest> request = allocator<_WindowCreationRequest>();
+    try {
+      request.ref.preferredSize.from(preferredSize);
+      request.ref.preferredConstraints.from(preferredConstraints);
+      request.ref.title = (title ?? 'Regular window').toNativeUtf16(allocator: allocator);
+      return _createWindow(engineId, request);
+    } finally {
+      allocator.free(request);
+    }
+  }
+
+  @ffi.Native<ffi.Int64 Function(ffi.Int64, ffi.Pointer<_WindowCreationRequest>)>(
+    symbol: 'InternalFlutterWindows_WindowManager_CreateRegularWindow',
+  )
+  external static int _createWindow(int engineId, ffi.Pointer<_WindowCreationRequest> request);
+
+  @ffi.Native<HWND Function(ffi.Int64, ffi.Int64)>(
+    symbol: 'InternalFlutterWindows_WindowManager_GetTopLevelWindowHandle',
+  )
+  external static HWND getWindowHandle(int engineId, int viewId);
+
+  @ffi.Native<ffi.Void Function(HWND)>(symbol: 'DestroyWindow')
+  external static void destroyWindow(HWND windowHandle);
+
+  @ffi.Native<_ActualContentSize Function(HWND)>(
+    symbol: 'InternalFlutterWindows_WindowManager_GetWindowContentSize',
+  )
+  external static _ActualContentSize getWindowContentSize(HWND windowHandle);
+
+  static void setWindowTitle(ffi.Allocator allocator, HWND windowHandle, String title) {
+    final ffi.Pointer<_Utf16> titlePointer = title.toNativeUtf16(allocator: allocator);
+    try {
+      _setWindowTitle(windowHandle, titlePointer);
+    } finally {
+      allocator.free(titlePointer);
+    }
+  }
+
+  @ffi.Native<ffi.Void Function(HWND, ffi.Pointer<_Utf16>)>(symbol: 'SetWindowTextW')
+  external static void _setWindowTitle(HWND windowHandle, ffi.Pointer<_Utf16> title);
+
+  static void setWindowContentSize(ffi.Allocator allocator, HWND windowHandle, Size? size) {
+    final ffi.Pointer<_WindowSizeRequest> request = allocator<_WindowSizeRequest>();
+    try {
+      request.ref.from(size);
+      _setWindowContentSize(windowHandle, request);
+    } finally {
+      allocator.free(request);
+    }
+  }
+
+  @ffi.Native<ffi.Void Function(HWND, ffi.Pointer<_WindowSizeRequest>)>(
+    symbol: 'InternalFlutterWindows_WindowManager_SetWindowSize',
+  )
+  external static void _setWindowContentSize(
+    HWND windowHandle,
+    ffi.Pointer<_WindowSizeRequest> size,
+  );
+
+  static void setWindowConstraints(
+    ffi.Allocator allocator,
+    HWND windowHandle,
+    BoxConstraints? constraints,
+  ) {
+    final ffi.Pointer<_WindowConstraintsRequest> request = allocator<_WindowConstraintsRequest>();
+    try {
+      request.ref.from(constraints);
+      _setWindowConstraints(windowHandle, request);
+    } finally {
+      allocator.free(request);
+    }
+  }
+
+  @ffi.Native<ffi.Void Function(HWND, ffi.Pointer<_WindowConstraintsRequest>)>(
+    symbol: 'InternalFlutterWindows_WindowManager_SetWindowConstraints',
+  )
+  external static void _setWindowConstraints(
+    HWND windowHandle,
+    ffi.Pointer<_WindowConstraintsRequest> constraints,
+  );
+
+  @ffi.Native<ffi.Void Function(HWND, ffi.Int32)>(symbol: 'ShowWindow')
+  external static void showWindow(HWND windowHandle, int command);
+
+  @ffi.Native<ffi.Int32 Function(HWND)>(symbol: 'IsIconic')
+  external static int isIconic(HWND windowHandle);
+
+  @ffi.Native<ffi.Int32 Function(HWND)>(symbol: 'IsZoomed')
+  external static int isZoomed(HWND windowHandle);
+
+  static void setFullscreen(
+    ffi.Allocator allocator,
+    HWND windowHandle,
+    bool fullscreen, {
+    Display? display,
+  }) {
+    final ffi.Pointer<_WindowFullscreenRequest> request = allocator<_WindowFullscreenRequest>();
+    try {
+      request.ref.fullscreen = fullscreen;
+      request.ref.hasDisplayId = display != null;
+      request.ref.displayId = display?.id ?? 0;
+      _setFullscreen(windowHandle, request);
+    } finally {
+      allocator.free(request);
+    }
+  }
+
+  @ffi.Native<ffi.Void Function(HWND, ffi.Pointer<_WindowFullscreenRequest>)>(
+    symbol: 'InternalFlutterWindows_WindowManager_SetFullscreen',
+  )
+  external static void _setFullscreen(
+    HWND windowHandle,
+    ffi.Pointer<_WindowFullscreenRequest> request,
+  );
+
+  @ffi.Native<ffi.Bool Function(HWND)>(symbol: 'InternalFlutterWindows_WindowManager_GetFullscreen')
+  external static bool getFullscreen(HWND windowHandle);
+
+  @ffi.Native<ffi.Int32 Function(HWND)>(symbol: 'GetWindowTextLengthW')
+  external static int _getWindowTextLength(HWND windowHandle);
+
+  @ffi.Native<ffi.Int32 Function(HWND, ffi.Pointer<_Utf16>, ffi.Int32)>(symbol: 'GetWindowTextW')
+  external static int _getWindowText(
+    HWND windowHandle,
+    ffi.Pointer<_Utf16> lpString,
+    int maxLength,
+  );
+
+  static String getWindowTitle(ffi.Allocator allocator, HWND windowHandle) {
+    final int length = _getWindowTextLength(windowHandle);
+    if (length == 0) {
+      return '';
+    }
+
+    final ffi.Pointer<ffi.Uint16> data = allocator<ffi.Uint16>(length + 1);
+    try {
+      final ffi.Pointer<_Utf16> buffer = data.cast<_Utf16>();
+      _getWindowText(windowHandle, buffer, length + 1);
+      return buffer.toDartString();
+    } finally {
+      allocator.free(data);
+    }
+  }
+
+  @ffi.Native<HWND Function()>(symbol: 'GetForegroundWindow')
+  external static HWND getForegroundWindow();
+}
+
+/// Payload for the creation method used by [_Win32PlatformInterface.createWindow].
+final class _WindowCreationRequest extends ffi.Struct {
+  external _WindowSizeRequest preferredSize;
+  external _WindowConstraintsRequest preferredConstraints;
+  external ffi.Pointer<_Utf16> title;
+}
+
+/// Payload for the initialization request for the windowing subsystem used
+/// by the constructor for [WindowingOwnerWin32].
+final class _WindowingInitRequest extends ffi.Struct {
+  external ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<_WindowsMessage>)>>
+  onMessage;
+}
+
+/// Payload for the size of a window used by [_WindowCreationRequest] and
+/// [_Win32PlatformInterface.setWindowContentSize].
+final class _WindowSizeRequest extends ffi.Struct {
+  @ffi.Bool()
+  external bool hasSize;
+
+  @ffi.Double()
+  external double width;
+
+  @ffi.Double()
+  external double height;
+
+  void from(Size? size) {
+    hasSize = size != null;
+    width = size?.width ?? 0;
+    height = size?.height ?? 0;
+  }
+}
+
+/// Payload for the constraints of a window used by [_WindowCreationRequest] and
+/// [_Win32PlatformInterface.setWindowConstraints].
+final class _WindowConstraintsRequest extends ffi.Struct {
+  @ffi.Bool()
+  external bool hasConstraints;
+
+  @ffi.Double()
+  external double minWidth;
+
+  @ffi.Double()
+  external double minHeight;
+
+  @ffi.Double()
+  external double maxWidth;
+
+  @ffi.Double()
+  external double maxHeight;
+
+  void from(BoxConstraints? constraints) {
+    hasConstraints = constraints != null;
+    minWidth = constraints?.minWidth ?? 0;
+    minHeight = constraints?.minHeight ?? 0;
+    maxWidth = constraints?.maxWidth ?? double.maxFinite;
+    maxHeight = constraints?.maxHeight ?? double.maxFinite;
+  }
+}
+
+/// A message received for all toplevel windows, used by [_WindowingInitRequest].
+final class _WindowsMessage extends ffi.Struct {
+  @ffi.Int64()
+  external int viewId;
+
+  external HWND windowHandle;
+
+  @ffi.Int32()
+  external int message;
+
+  @ffi.Int64()
+  external int wParam;
+
+  @ffi.Int64()
+  external int lParam;
+
+  @ffi.Int64()
+  external int lResult;
+
+  @ffi.Bool()
+  external bool handled;
+}
+
+/// Holds the real size of a window as retrieved from
+/// [_Win32PlatformInterface.getWindowContentSize].
+final class _ActualContentSize extends ffi.Struct {
+  @ffi.Double()
+  external double width;
+
+  @ffi.Double()
+  external double height;
+}
+
+/// Payload for the [_Win32PlatformInterface.setFullscreen] request.
+final class _WindowFullscreenRequest extends ffi.Struct {
+  @ffi.Bool()
+  external bool fullscreen;
+
+  @ffi.Bool()
+  external bool hasDisplayId;
+
+  @ffi.Uint64()
+  external int displayId;
+}
+
+/// The contents of a native zero-terminated array of UTF-16 code units.
+///
+/// The Utf16 type itself has no functionality, it's only intended to be used
+/// through a `Pointer<Utf16>` representing the entire array. This pointer is
+/// the equivalent of a char pointer (`const wchar_t*`) in C code. The
+/// individual UTF-16 code units are stored in native byte order.
+final class _Utf16 extends ffi.Opaque {}
+
+/// Extension method for converting a`Pointer<Utf16>` to a [String].
+extension _Utf16Pointer on ffi.Pointer<_Utf16> {
+  /// Converts this UTF-16 encoded string to a Dart string.
+  ///
+  /// Decodes the UTF-16 code units of this zero-terminated code unit array as
+  /// Unicode code points and creates a Dart string containing those code
+  /// points.
+  ///
+  /// If [length] is provided, zero-termination is ignored and the result can
+  /// contain NUL characters.
+  ///
+  /// If [length] is not provided, the returned string is the string up til
+  /// but not including the first NUL character.
+  String toDartString({int? length}) {
+    _ensureNotNullptr('toDartString');
+    final ffi.Pointer<ffi.Uint16> codeUnits = cast<ffi.Uint16>();
+    if (length == null) {
+      return _toUnknownLengthString(codeUnits);
+    } else {
+      RangeError.checkNotNegative(length, 'length');
+      return _toKnownLengthString(codeUnits, length);
+    }
+  }
+
+  static String _toKnownLengthString(ffi.Pointer<ffi.Uint16> codeUnits, int length) =>
+      String.fromCharCodes(codeUnits.asTypedList(length));
+
+  static String _toUnknownLengthString(ffi.Pointer<ffi.Uint16> codeUnits) {
+    final StringBuffer buffer = StringBuffer();
+    int i = 0;
+    while (true) {
+      final int char = (codeUnits + i).value;
+      if (char == 0) {
+        return buffer.toString();
+      }
+      buffer.writeCharCode(char);
+      i++;
+    }
+  }
+
+  void _ensureNotNullptr(String operation) {
+    if (this == ffi.nullptr) {
+      throw UnsupportedError("Operation '$operation' not allowed on a 'nullptr'.");
+    }
+  }
+}
+
+/// Extension method for converting a [String] to a `Pointer<Utf16>`.
+extension _StringUtf16Pointer on String {
+  /// Creates a zero-terminated [Utf16] code-unit array from this String.
+  ///
+  /// If this [String] contains NUL characters, converting it back to a string
+  /// using [Utf16Pointer.toDartString] will truncate the result if a length is
+  /// not passed.
+  ///
+  /// Returns an [allocator]-allocated pointer to the result.
+  ffi.Pointer<_Utf16> toNativeUtf16({required ffi.Allocator allocator}) {
+    final List<int> units = codeUnits;
+    final ffi.Pointer<ffi.Uint16> result = allocator<ffi.Uint16>(units.length + 1);
+    final Uint16List nativeString = result.asTypedList(units.length + 1);
+    nativeString.setRange(0, units.length, units);
+    nativeString[units.length] = 0;
+    return result.cast();
+  }
+}
+
+typedef _WinCoTaskMemAllocNative = ffi.Pointer<ffi.NativeType> Function(ffi.Size);
+typedef _WinCoTaskMemAlloc = ffi.Pointer<ffi.NativeType> Function(int);
+typedef _WinCoTaskMemFreeNative = ffi.Void Function(ffi.Pointer<ffi.NativeType>);
+typedef _WinCoTaskMemFree = void Function(ffi.Pointer<ffi.NativeType>);
+
+final class _CallocAllocator implements ffi.Allocator {
+  _CallocAllocator() {
+    _ole32lib = ffi.DynamicLibrary.open('ole32.dll');
+    _winCoTaskMemAlloc = _ole32lib.lookupFunction<_WinCoTaskMemAllocNative, _WinCoTaskMemAlloc>(
+      'CoTaskMemAlloc',
+    );
+    _winCoTaskMemFreePointer = _ole32lib.lookup('CoTaskMemFree');
+    _winCoTaskMemFree = _winCoTaskMemFreePointer.asFunction();
+  }
+
+  late final ffi.DynamicLibrary _ole32lib;
+  late final _WinCoTaskMemAlloc _winCoTaskMemAlloc;
+  late final ffi.Pointer<ffi.NativeFunction<_WinCoTaskMemFreeNative>> _winCoTaskMemFreePointer;
+  late final _WinCoTaskMemFree _winCoTaskMemFree;
+
+  /// Fills a block of memory with a specified value.
+  // ignore: always_specify_types
+  void _fillMemory(ffi.Pointer destination, int length, int fill) {
+    final ffi.Pointer<ffi.Uint8> ptr = destination.cast<ffi.Uint8>();
+    for (int i = 0; i < length; i++) {
+      ptr[i] = fill;
+    }
+  }
+
+  /// Fills a block of memory with zeros.
+  // ignore: always_specify_types
+  void _zeroMemory(ffi.Pointer destination, int length) => _fillMemory(destination, length, 0);
+
+  /// Allocates [byteCount] bytes of zero-initialized of memory on the native
+  /// heap.
+  @override
+  ffi.Pointer<T> allocate<T extends ffi.NativeType>(int byteCount, {int? alignment}) {
+    ffi.Pointer<T> result;
+    result = _winCoTaskMemAlloc(byteCount).cast();
+    if (result.address == 0) {
+      throw ArgumentError('Could not allocate $byteCount bytes.');
+    }
+    if (Platform.isWindows) {
+      _zeroMemory(result, byteCount);
+    }
+    return result;
+  }
+
+  /// Releases memory allocated on the native heap.
+  @override
+  // ignore: always_specify_types
+  void free(ffi.Pointer pointer) {
+    _winCoTaskMemFree(pointer);
+  }
+
+  /// Returns a pointer to a native free function.
+  ffi.Pointer<ffi.NativeFinalizerFunction> get nativeFree => _winCoTaskMemFreePointer;
+}
diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart
index 61e8030..4152d0f 100644
--- a/packages/flutter/lib/src/widgets/binding.dart
+++ b/packages/flutter/lib/src/widgets/binding.dart
@@ -461,7 +461,7 @@
       return true;
     }());
     platformMenuDelegate = DefaultPlatformMenuDelegate();
-    _windowingOwner = WindowingOwner.createDefaultOwner();
+    _windowingOwner = createDefaultWindowingOwner();
   }
 
   /// The current [WidgetsBinding], if one has been created.
diff --git a/packages/flutter/test/widgets/windowing_test.dart b/packages/flutter/test/widgets/windowing_test.dart
index aec8eef..ca8995b 100644
--- a/packages/flutter/test/widgets/windowing_test.dart
+++ b/packages/flutter/test/widgets/windowing_test.dart
@@ -11,7 +11,8 @@
         RegularWindowController,
         RegularWindowControllerDelegate,
         WindowScope,
-        WindowingOwner;
+        WindowingOwner,
+        createDefaultWindowingOwner;
 import 'package:flutter/widgets.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -73,12 +74,12 @@
       });
 
       test('createDefaultOwner returns a WindowingOwner', () {
-        final WindowingOwner owner = WindowingOwner.createDefaultOwner();
+        final WindowingOwner owner = createDefaultWindowingOwner();
         expect(owner, isA<WindowingOwner>());
       });
 
       test('default WindowingOwner throws when accessing createRegularWindowController', () {
-        final WindowingOwner owner = WindowingOwner.createDefaultOwner();
+        final WindowingOwner owner = createDefaultWindowingOwner();
         expect(
           () => owner.createRegularWindowController(delegate: RegularWindowControllerDelegate()),
           throwsUnsupportedError,
@@ -86,7 +87,7 @@
       });
 
       test('default WindowingOwner throws when accessing hasTopLevelWindows', () {
-        final WindowingOwner owner = WindowingOwner.createDefaultOwner();
+        final WindowingOwner owner = createDefaultWindowingOwner();
         expect(() => owner.hasTopLevelWindows(), throwsUnsupportedError);
       });
 
@@ -110,23 +111,22 @@
         isWindowingEnabled = true;
       });
 
-      test('createDefaultOwner returns a WindowingOwner', () {
-        final WindowingOwner owner = WindowingOwner.createDefaultOwner();
-        expect(owner, isA<WindowingOwner>());
-      });
-
       testWidgets('RegularWindow does not throw', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
-          RegularWindow(controller: _StubWindowController(tester), child: Container()),
+          RegularWindow(controller: controller, child: Container()),
         );
       });
 
       testWidgets('Can access WindowScope.of', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final BaseWindowController scope = WindowScope.of(context);
@@ -139,10 +139,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final BaseWindowController? scope = WindowScope.maybeOf(context);
@@ -155,10 +157,12 @@
       });
 
       testWidgets('Can access WindowScope.contentSizeOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final Size size = WindowScope.contentSizeOf(context);
@@ -171,10 +175,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeContentSizeOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final Size? size = WindowScope.maybeContentSizeOf(context);
@@ -187,10 +193,12 @@
       });
 
       testWidgets('Can access WindowScope.titleOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final String title = WindowScope.titleOf(context);
@@ -203,10 +211,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeTitleOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final String? title = WindowScope.maybeTitleOf(context);
@@ -219,10 +229,12 @@
       });
 
       testWidgets('Can access WindowScope.isActivatedOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool isActivated = WindowScope.isActivatedOf(context);
@@ -235,10 +247,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeIsActivatedOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool? isActivated = WindowScope.maybeIsActivatedOf(context);
@@ -251,10 +265,12 @@
       });
 
       testWidgets('Can access WindowScope.isMinimizedOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool isMinimized = WindowScope.isMinimizedOf(context);
@@ -267,10 +283,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeIsMinimizedOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool? isMinimized = WindowScope.maybeIsMinimizedOf(context);
@@ -283,10 +301,12 @@
       });
 
       testWidgets('Can access WindowScope.isMaximizedOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool isMaximized = WindowScope.isMaximizedOf(context);
@@ -299,10 +319,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeIsMaximizedOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool? isMaximized = WindowScope.maybeIsMaximizedOf(context);
@@ -315,10 +337,12 @@
       });
 
       testWidgets('Can access WindowScope.isFullscreenOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool isFullscreen = WindowScope.isFullscreenOf(context);
@@ -331,10 +355,12 @@
       });
 
       testWidgets('Can access WindowScope.maybeIsFullscreenOf', (WidgetTester tester) async {
+        final _StubWindowController controller = _StubWindowController(tester);
+        addTearDown(controller.dispose);
         await tester.pumpWidget(
           wrapWithView: false,
           RegularWindow(
-            controller: _StubWindowController(tester),
+            controller: controller,
             child: Builder(
               builder: (BuildContext context) {
                 final bool? isFullscreen = WindowScope.maybeIsFullscreenOf(context);
diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart
index 5148942..78e7af5 100644
--- a/packages/flutter_test/lib/src/window.dart
+++ b/packages/flutter_test/lib/src/window.dart
@@ -175,6 +175,9 @@
         : null;
   }
 
+  @override
+  int? get engineId => 1;
+
   final Map<int, TestFlutterView> _testViews = <int, TestFlutterView>{};
   final Map<int, TestDisplay> _testDisplays = <int, TestDisplay>{};