| // Copyright (c) 2026, the Dart project authors. 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. |
| |
| /// Used by the `wind32_integration_test.ps1` script to verify that |
| /// `Win32AnsiStdin` works as expected on Windows powershell. |
| library; |
| |
| import 'dart:convert'; |
| import 'dart:ffi'; |
| import 'dart:io'; |
| import 'package:cli_util/src/windows/win32_stdin.dart'; |
| import 'package:ffi/ffi.dart'; |
| |
| void main(List<String> args) async { |
| if (args.isEmpty) { |
| stderr.writeln('Usage: echo_stdin.dart <output_file>'); |
| exit(1); |
| } |
| |
| final filePath = args.first; |
| final file = File(filePath); |
| |
| // Ensure file is cleared or created |
| file.writeAsStringSync(''); |
| |
| // Detach from current console and attach to parent console to ensure we can |
| // read input in CI. |
| try { |
| final kernel32 = DynamicLibrary.open('kernel32.dll'); |
| final freeConsole = kernel32 |
| .lookupFunction<Int32 Function(), int Function()>('FreeConsole'); |
| final attachConsole = kernel32 |
| .lookupFunction<Int32 Function(Uint32), int Function(int)>( |
| 'AttachConsole', |
| ); |
| |
| freeConsole(); |
| attachConsole(0xFFFFFFFF); // ATTACH_PARENT_PROCESS |
| } catch (e) { |
| // Ignore errors |
| } |
| |
| // Open CONIN$ to get a valid console handle, bypassing GetStdHandle which |
| // might be redirected. |
| var coninHandle = -1; |
| try { |
| final kernel32 = DynamicLibrary.open('kernel32.dll'); |
| final createFileW = kernel32.lookupFunction< |
| IntPtr Function( |
| Pointer<Utf16>, |
| Uint32, |
| Uint32, |
| Pointer, |
| Uint32, |
| Uint32, |
| IntPtr, |
| ), |
| int Function(Pointer<Utf16>, int, int, Pointer, int, int, int) |
| >('CreateFileW'); |
| |
| final coninPath = r'CONIN$'.toNativeUtf16(); |
| coninHandle = createFileW( |
| coninPath, |
| 0x80000000 | 0x40000000, // GENERIC_READ | GENERIC_WRITE |
| 1, // FILE_SHARE_READ |
| nullptr, |
| 3, // OPEN_EXISTING |
| 0, |
| 0, |
| ); |
| |
| calloc.free(coninPath); |
| } catch (e) { |
| // Ignore errors |
| } |
| |
| final subscription = Win32AnsiStdin( |
| coninHandle == -1 ? null : coninHandle, |
| ).listen((data) { |
| file.writeAsStringSync('${jsonEncode(data)}\r\n', mode: FileMode.append); |
| }); |
| |
| file.writeAsStringSync('READY\r\n', mode: FileMode.append); |
| |
| // Keep process alive to receive events. |
| // It will be killed by the powershell script. |
| await Future<void>.delayed(const Duration(seconds: 30)); |
| |
| await subscription.cancel(); |
| } |