From bbeebe97e95d9cca911dc4bd4798973d385d353a Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Wed, 3 Jun 2026 02:58:31 +0200 Subject: [PATCH 1/2] core: migrate to win32 v6 --- analysis_options.yaml | 3 ++ lib/src/windows_single_instance.dart | 52 ++++++++++++++++++---------- pubspec.yaml | 8 ++--- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a5744c1..5e91e85 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,3 +2,6 @@ include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options + +formatter: + trailing_commas: preserve diff --git a/lib/src/windows_single_instance.dart b/lib/src/windows_single_instance.dart index dbe2c41..7647725 100644 --- a/lib/src/windows_single_instance.dart +++ b/lib/src/windows_single_instance.dart @@ -4,8 +4,9 @@ import 'dart:ffi'; import 'dart:io'; import 'dart:isolate'; -import 'package:ffi/ffi.dart'; import 'package:flutter/services.dart'; + +import 'package:ffi/ffi.dart'; import 'package:win32/win32.dart'; class WindowsSingleInstance { @@ -14,40 +15,53 @@ class WindowsSingleInstance { WindowsSingleInstance._(); - static int _openPipe(String filename) { - final cPipe = filename.toNativeUtf16(); + static HANDLE _openPipe(String filename) { + final cPipe = filename.toPcwstr(); try { - return CreateFile(cPipe, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, 0); + final Win32Result(:value) = CreateFile( + cPipe, + GENERIC_WRITE, + FILE_SHARE_NONE, + null, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + null, + ); + return value; } finally { free(cPipe); } } - static int _createPipe(String filename) { - final cPipe = filename.toNativeUtf16(); + static HANDLE _createPipe(String filename) { + final cPipe = filename.toPcwstr(); try { return CreateNamedPipe( cPipe, - PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + FILE_FLAGS_AND_ATTRIBUTES( + PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + ), + NAMED_PIPE_MODE( + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + ), PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, - nullptr, + null, ); } finally { - malloc.free(cPipe); + free(cPipe); } } - static void _readPipe(SendPort writer, int pipeHandle) { + static void _readPipe(SendPort writer, HANDLE pipeHandle) { final overlap = calloc(); try { while (true) { while (true) { - ConnectNamedPipe(pipeHandle, overlap); - final err = GetLastError(); + final Win32Result(:error) = ConnectNamedPipe(pipeHandle, overlap); + final err = error; if (err == _kErrorPipeConnected) { sleep(const Duration(milliseconds: 200)); continue; @@ -57,11 +71,11 @@ class WindowsSingleInstance { break; } - var dataSize = 16384; - var data = calloc(dataSize); + const dataSize = 16384; + final data = calloc(dataSize); final numRead = calloc(); try { - while (GetOverlappedResult(pipeHandle, overlap, numRead, 0) == 0) { + while (!GetOverlappedResult(pipeHandle, overlap, numRead, false).value) { sleep(const Duration(milliseconds: 200)); } @@ -85,9 +99,9 @@ class WindowsSingleInstance { final pipe = _openPipe(filename); final bytesString = jsonEncode(arguments ?? []); final bytes = bytesString.toNativeUtf8(); - final numWritten = malloc(); + final numWritten = calloc(); try { - WriteFile(pipe, bytes.cast(), bytes.length, numWritten, nullptr); + WriteFile(pipe, bytes.cast(), bytes.length, numWritten, null); } finally { free(numWritten); free(bytes); @@ -104,7 +118,7 @@ class WindowsSingleInstance { _readPipe(args["port"] as SendPort, pipe); } - /// Checks that the current window is unique, and exits the app not. + /// Checks that the current window is unique, and exits the app if not. /// /// __Arguments__\ /// `arguments`: List of strings that will be passed to the callback function of the open instance if this window is not unique\ diff --git a/pubspec.yaml b/pubspec.yaml index 5936e23..5b0bf54 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,23 +1,23 @@ name: windows_single_instance description: Forces a single instance of your Windows app, bringing the existing window to the front when a new instance is opened. -version: 1.1.0 +version: 2.0.0 homepage: https://github.com/SongbookPro/flutter_windows_single_instance environment: - sdk: ">=2.16.2 <4.0.0" + sdk: ">=3.11.0 <4.0.0" flutter: ">=2.5.0" dependencies: flutter: sdk: flutter - win32: ">=2.5.0 <6.0.0" + win32: ^6.3.0 ffi: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^6.0.0 flutter: plugin: From 1da5270ec4ae2b8ec6cb4752085fdabcc98ae8ca Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Wed, 3 Jun 2026 03:44:18 +0200 Subject: [PATCH 2/2] fix: use `malloc` --- lib/src/windows_single_instance.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/windows_single_instance.dart b/lib/src/windows_single_instance.dart index 7647725..5b309bd 100644 --- a/lib/src/windows_single_instance.dart +++ b/lib/src/windows_single_instance.dart @@ -99,7 +99,7 @@ class WindowsSingleInstance { final pipe = _openPipe(filename); final bytesString = jsonEncode(arguments ?? []); final bytes = bytesString.toNativeUtf8(); - final numWritten = calloc(); + final numWritten = malloc(); try { WriteFile(pipe, bytes.cast(), bytes.length, numWritten, null); } finally { diff --git a/pubspec.yaml b/pubspec.yaml index 5b0bf54..40eb08d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: windows_single_instance description: Forces a single instance of your Windows app, bringing the existing window to the front when a new instance is opened. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/SongbookPro/flutter_windows_single_instance environment: