import 'dart:ffi'; import 'dart:io'; import 'package:ffi/ffi.dart'; // 약속 (나누기 file_ops): Windows 저장 장치 - 드라이브 목록 · 드라이브 종류 · 네트워크 공유의 맨 위. // 입력: 드라이브 맨 위 ("C:\") · 경로. 출력: 목록 · 종류 번호 · 글. // 오류: 던지지 않는다. Windows API 를 부르지 못하면 [windowsDrives] 는 C: 하나, [driveType] 은 0 (모름). // 드라이브를 열어 보지 않는다 (끊긴 네트워크 드라이브에서 멈추지 않게). /// 저장 장치 (맨 위 폴더): Windows 는 드라이브 (C:\ …), 그 밖은 주어진 목록. /// 165: 드라이브 문자는 Windows 가 알려 주는 목록 (GetLogicalDrives) 으로 - 드라이브마다 열어 보지 않는다 /// (끊긴 · 느린 네트워크 드라이브 (NAS) 를 열어 보느라 탐색기가 10초씩 멈췄다) List<(String path, String label)> windowsDrives() { int mask; try { mask = DynamicLibrary.open('kernel32.dll').lookupFunction('GetLogicalDrives')(); } catch (_) { mask = 0; } if (mask == 0) return [(r'C:\', 'C:')]; return [ for (final c in 'CDEFGHIJKLMNOPQRSTUVWXYZAB'.split('')) if (mask & (1 << (c.codeUnitAt(0) - 65)) != 0) ('$c:\\', '$c:'), ]; } /// 165: 드라이브 종류 (GetDriveTypeW: 2 꺼내는 장치 (카드 리더 · USB) · 3 고정 · 4 네트워크 · 5 CD). 드라이브를 열어 보지 않는다. 모르면 0 int driveType(String root) { if (!Platform.isWindows) return 0; final w = root.toNativeUtf16(); try { final f = DynamicLibrary.open('kernel32.dll') .lookupFunction), int Function(Pointer)>('GetDriveTypeW'); return f(w); } catch (_) { return 0; } finally { calloc.free(w); } } /// 네트워크 드라이브인지 bool isNetworkDrive(String root) => driveType(root) == 4; /// Windows 네트워크 공유 경로의 맨 위 (\\서버\공유). 37 String uncRoot(String path) { final parts = path.replaceAll('/', r'\').split(r'\').where((s) => s.isNotEmpty).toList(); return parts.length < 2 ? path : '\\\\${parts[0]}\\${parts[1]}'; }