-
Notifications
You must be signed in to change notification settings - Fork 5
/
win32_runner.dart
125 lines (108 loc) · 3.97 KB
/
win32_runner.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright (c) 2023, Halil Durmus. Please see the AUTHORS file for details.
// 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:ffi';
import 'dart:io';
import 'dart:math' as math;
import 'package:args/args.dart';
import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart';
import 'package:win32_runner/win32_runner.dart';
void main() => initApp(Application.winMain);
class Application {
static late FlutterEmbedder engine;
static bool engineInitialized = false;
static int mainWindowProc(int hwnd, int msg, int wParam, int lParam) {
// Give Flutter an opportunity to handle window messages.
if (engineInitialized) {
final result = engine.handleTopLevelWindowProc(hwnd, msg, wParam, lParam);
if (result != FALSE) return result;
}
// Otherwise, we address host window messages.
switch (msg) {
case WM_NCCREATE:
EnableNonClientDpiScaling(hwnd);
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_FONTCHANGE:
engine.reloadSystemFonts();
return 0;
case WM_SIZE:
final hostWindow = Window(hwnd);
Window(engine.hwnd).move(hostWindow.dimensions);
return 0;
case WM_ACTIVATE:
Window(engine.hwnd).setFocus();
return 0;
case WM_SETTINGCHANGE:
if (wParam == 0 && lParam != 0) {
final lParamString =
Pointer.fromAddress(lParam).cast<Utf16>().toDartString();
if (lParamString == 'ImmersiveColorSet') {
Window(hwnd).updateTheme();
}
}
return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
Window(hwnd).updateTheme();
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
static String parseArgs(List<String> args) {
final parser = ArgParser()
..addOption('path',
abbr: 'p',
help: 'Relative or absolute path to a Flutter app. ',
defaultsTo: '.')
..addFlag('help', abbr: 'h', help: 'Shows usage information.');
final results = parser.parse(args);
if (results['help'] as bool) {
print('Runs a Flutter app.\n\nSyntax:\n${parser.usage}');
exit(0);
}
final appPath = results['path'] as String;
return Directory(appPath).absolute.path;
}
static void winMain(int hInstance, List<String> args, int nShowCmd) {
final appPath = parseArgs(args);
final iconPath = '$appPath\\windows\\runner\\resources\\app_icon.ico';
if (!File(iconPath).existsSync()) {
print('Icon file not found at "$iconPath".');
exit(WIN32_ERROR.ERROR_FILE_NOT_FOUND);
}
CoInitializeEx(nullptr, COINIT.COINIT_APARTMENTTHREADED);
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
final windowProc = NativeCallable<WNDPROC>.isolateLocal(
mainWindowProc,
exceptionalReturn: 0,
);
final hostWindow = Window.create(
hInstance: hInstance,
windowCaption: 'Dart Native Win32 Window',
className: 'FLUTTER_RUNNER_WIN32_WINDOW',
windowProc: windowProc.nativeFunction,
dimensions: const math.Rectangle<int>(10, 10, 1280, 720),
iconPath: iconPath,
)..updateTheme();
final project = DartProject.fromRoot(appPath);
final flutterLibrary =
'$appPath\\windows\\flutter\\ephemeral\\flutter_windows.dll';
if (!File(flutterLibrary).existsSync()) {
print('`flutter_windows.dll` file not found at "$flutterLibrary".');
exit(WIN32_ERROR.ERROR_FILE_NOT_FOUND);
}
// Set up Flutter view controller. The size must match the window dimensions
// to avoid unnecessary surface creation / destruction in the startup path.
engine = FlutterEmbedder(hostWindow.dimensions, project, flutterLibrary);
engineInitialized = true;
Window(engine.hwnd)
..setParent(hostWindow)
..move(hostWindow.dimensions)
..setFocus()
..runMessageLoop();
windowProc.close();
CoUninitialize();
}
}