From 47a92dbdea9bc433779c76b404af9c5ab6fa40cc Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 9 Jul 2024 06:03:23 -0400 Subject: [PATCH] [path_provider] Remove `win32` (#7073) Per https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#dependencies, we generally do not want third-party dependencies. `path_provider` in particular is a key part of the ecosystem (well over 1,000 packages depend directly on it, and transitively it's probably several times that at least), and thus the maintenance and security considerations are particularly acute. This eliminates the dependency on `win32`, a large third-party dependency, in favor of direct FFI code written from scratch using the official Win32 reference documentation from Microsoft as the source. The only behavioral change that should result here is that the exceptions thrown in failure cases have changed, but they were never documented, and were entirely platform-specific, so it's relatively unlikely that people will be broken by that. (As noted in a TODO, the longer term solution is to provide real exceptions for this package, and use those across platforms.) Fixes https://github.com/flutter/flutter/issues/130940 --- .../path_provider_windows/CHANGELOG.md | 3 +- .../lib/src/folders.dart | 115 ++++++++++-------- .../path_provider_windows/lib/src/guid.dart | 51 ++++++++ .../lib/src/path_provider_windows_real.dart | 33 +++-- .../lib/src/win32_wrappers.dart | 112 +++++++++++++++++ .../path_provider_windows/pubspec.yaml | 3 +- .../path_provider_windows/test/guid_test.dart | 63 ++++++++++ script/configs/allowed_unpinned_deps.yaml | 1 - 8 files changed, 314 insertions(+), 67 deletions(-) create mode 100644 packages/path_provider/path_provider_windows/lib/src/guid.dart create mode 100644 packages/path_provider/path_provider_windows/lib/src/win32_wrappers.dart create mode 100644 packages/path_provider/path_provider_windows/test/guid_test.dart diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index 933fe1f1d81c4..46e7ac64ac2d8 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.3.0 +* Replaces `win32` dependency with direct FFI usage. * Updates minimum supported SDK version to Flutter 3.16/Dart 3.2. ## 2.2.1 diff --git a/packages/path_provider/path_provider_windows/lib/src/folders.dart b/packages/path_provider/path_provider_windows/lib/src/folders.dart index 55def29df2d77..022aba45d602d 100644 --- a/packages/path_provider/path_provider_windows/lib/src/folders.dart +++ b/packages/path_provider/path_provider_windows/lib/src/folders.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:win32/win32.dart'; - // ignore_for_file: non_constant_identifier_names // ignore: avoid_classes_with_only_static_members @@ -11,122 +9,127 @@ import 'package:win32/win32.dart'; /// known folders. A property of this class may be passed to the `getPath` /// method in the [PathProvidersWindows] class to retrieve a known folder from /// Windows. +// These constants come from +// https://learn.microsoft.com/windows/win32/shell/knownfolderid class WindowsKnownFolder { /// The file system directory that is used to store administrative tools for /// an individual user. The MMC will save customized consoles to this /// directory, and it will roam with the user. - static String get AdminTools => FOLDERID_AdminTools; + static String get AdminTools => '{724EF170-A42D-4FEF-9F26-B60E846FBA4F}'; /// The file system directory that acts as a staging area for files waiting to /// be written to a CD. A typical path is C:\Documents and /// Settings\username\Local Settings\Application Data\Microsoft\CD Burning. - static String get CDBurning => FOLDERID_CDBurning; + static String get CDBurning => '{9E52AB10-F80D-49DF-ACB8-4330F5687855}'; /// The file system directory that contains administrative tools for all users /// of the computer. - static String get CommonAdminTools => FOLDERID_CommonAdminTools; + static String get CommonAdminTools => + '{D0384E7D-BAC3-4797-8F14-CBA229B392B5}'; /// The file system directory that contains the directories for the common /// program groups that appear on the Start menu for all users. A typical path /// is C:\Documents and Settings\All Users\Start Menu\Programs. - static String get CommonPrograms => FOLDERID_CommonPrograms; + static String get CommonPrograms => '{0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8}'; /// The file system directory that contains the programs and folders that /// appear on the Start menu for all users. A typical path is C:\Documents and /// Settings\All Users\Start Menu. - static String get CommonStartMenu => FOLDERID_CommonStartMenu; + static String get CommonStartMenu => '{A4115719-D62E-491D-AA7C-E74B8BE3B067}'; /// The file system directory that contains the programs that appear in the /// Startup folder for all users. A typical path is C:\Documents and /// Settings\All Users\Start Menu\Programs\Startup. - static String get CommonStartup => FOLDERID_CommonStartup; + static String get CommonStartup => '{82A5EA35-D9CD-47C5-9629-E15D2F714E6E}'; /// The file system directory that contains the templates that are available /// to all users. A typical path is C:\Documents and Settings\All /// Users\Templates. - static String get CommonTemplates => FOLDERID_CommonTemplates; + static String get CommonTemplates => '{B94237E7-57AC-4347-9151-B08C6C32D1F7}'; /// The virtual folder that represents My Computer, containing everything on /// the local computer: storage devices, printers, and Control Panel. The /// folder can also contain mapped network drives. - static String get ComputerFolder => FOLDERID_ComputerFolder; + static String get ComputerFolder => '{0AC0837C-BBF8-452A-850D-79D08E667CA7}'; /// The virtual folder that represents Network Connections, that contains /// network and dial-up connections. - static String get ConnectionsFolder => FOLDERID_ConnectionsFolder; + static String get ConnectionsFolder => + '{6F0CD92B-2E97-45D1-88FF-B0D186B8DEDD}'; /// The virtual folder that contains icons for the Control Panel applications. - static String get ControlPanelFolder => FOLDERID_ControlPanelFolder; + static String get ControlPanelFolder => + '{82A74AEB-AEB4-465C-A014-D097EE346D63}'; /// The file system directory that serves as a common repository for Internet /// cookies. A typical path is C:\Documents and Settings\username\Cookies. - static String get Cookies => FOLDERID_Cookies; + static String get Cookies => '{2B0F765D-C0E9-4171-908E-08A611B84FF6}'; /// The virtual folder that represents the Windows desktop, the root of the /// namespace. - static String get Desktop => FOLDERID_Desktop; + static String get Desktop => '{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}'; /// The virtual folder that represents the My Documents desktop item. - static String get Documents => FOLDERID_Documents; + static String get Documents => '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}'; /// The file system directory that serves as a repository for Internet /// downloads. - static String get Downloads => FOLDERID_Downloads; + static String get Downloads => '{374DE290-123F-4565-9164-39C4925E467B}'; /// The file system directory that serves as a common repository for the /// user's favorite items. A typical path is C:\Documents and /// Settings\username\Favorites. - static String get Favorites => FOLDERID_Favorites; + static String get Favorites => '{1777F761-68AD-4D8A-87BD-30B759FA33DD}'; /// A virtual folder that contains fonts. A typical path is C:\Windows\Fonts. - static String get Fonts => FOLDERID_Fonts; + static String get Fonts => '{FD228CB7-AE11-4AE3-864C-16F3910AB8FE}'; /// The file system directory that serves as a common repository for Internet /// history items. - static String get History => FOLDERID_History; + static String get History => '{D9DC8A3B-B784-432E-A781-5A1130A75963}'; /// The file system directory that serves as a common repository for temporary /// Internet files. A typical path is C:\Documents and Settings\username\Local /// Settings\Temporary Internet Files. - static String get InternetCache => FOLDERID_InternetCache; + static String get InternetCache => '{352481E8-33BE-4251-BA85-6007CAEDCF9D}'; /// A virtual folder for Internet Explorer. - static String get InternetFolder => FOLDERID_InternetFolder; + static String get InternetFolder => '{4D9F7874-4E0C-4904-967B-40B0D20C3E4B}'; /// The file system directory that serves as a data repository for local /// (nonroaming) applications. A typical path is C:\Documents and /// Settings\username\Local Settings\Application Data. - static String get LocalAppData => FOLDERID_LocalAppData; + static String get LocalAppData => '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}'; /// The file system directory that serves as a common repository for music /// files. A typical path is C:\Documents and Settings\User\My Documents\My /// Music. - static String get Music => FOLDERID_Music; + static String get Music => '{4BD8D571-6D19-48D3-BE97-422220080E43}'; /// A file system directory that contains the link objects that may exist in /// the My Network Places virtual folder. A typical path is C:\Documents and /// Settings\username\NetHood. - static String get NetHood => FOLDERID_NetHood; + static String get NetHood => '{C5ABBF53-E17F-4121-8900-86626FC2C973}'; /// The folder that represents other computers in your workgroup. - static String get NetworkFolder => FOLDERID_NetworkFolder; + static String get NetworkFolder => '{D20BEEC4-5CA8-4905-AE3B-BF251EA09B53}'; /// The file system directory that serves as a common repository for image /// files. A typical path is C:\Documents and Settings\username\My /// Documents\My Pictures. - static String get Pictures => FOLDERID_Pictures; + static String get Pictures => '{33E28130-4E1E-4676-835A-98395C3BC3BB}'; /// The file system directory that contains the link objects that can exist in /// the Printers virtual folder. A typical path is C:\Documents and /// Settings\username\PrintHood. - static String get PrintHood => FOLDERID_PrintHood; + static String get PrintHood => '{9274BD8D-CFD1-41C3-B35E-B13F55A758F4}'; /// The virtual folder that contains installed printers. - static String get PrintersFolder => FOLDERID_PrintersFolder; + static String get PrintersFolder => '{76FC4E2D-D6AD-4519-A663-37BD56068185}'; /// The user's profile folder. A typical path is C:\Users\username. /// Applications should not create files or folders at this level. - static String get Profile => FOLDERID_Profile; + static String get Profile => '{5E6C858F-0E22-4760-9AFE-EA3317B67173}'; /// The file system directory that contains application data for all users. A /// typical path is C:\Documents and Settings\All Users\Application Data. This @@ -134,110 +137,114 @@ class WindowsKnownFolder { /// example, an application can store a spell-check dictionary, a database of /// clip art, or a log file in the CSIDL_COMMON_APPDATA folder. This /// information will not roam and is available to anyone using the computer. - static String get ProgramData => FOLDERID_ProgramData; + static String get ProgramData => '{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}'; /// The Program Files folder. A typical path is C:\Program Files. - static String get ProgramFiles => FOLDERID_ProgramFiles; + static String get ProgramFiles => '{905e63b6-c1bf-494e-b29c-65b732d3d21a}'; /// The common Program Files folder. A typical path is C:\Program /// Files\Common. - static String get ProgramFilesCommon => FOLDERID_ProgramFilesCommon; + static String get ProgramFilesCommon => + '{F7F1ED05-9F6D-47A2-AAAE-29D317C6F066}'; /// On 64-bit systems, a link to the common Program Files folder. A typical path is /// C:\Program Files\Common Files. - static String get ProgramFilesCommonX64 => FOLDERID_ProgramFilesCommonX64; + static String get ProgramFilesCommonX64 => + '{6365D5A7-0F0D-45e5-87F6-0DA56B6A4F7D}'; /// On 64-bit systems, a link to the 32-bit common Program Files folder. A /// typical path is C:\Program Files (x86)\Common Files. On 32-bit systems, a /// link to the Common Program Files folder. - static String get ProgramFilesCommonX86 => FOLDERID_ProgramFilesCommonX86; + static String get ProgramFilesCommonX86 => + '{DE974D24-D9C6-4D3E-BF91-F4455120B917}'; /// On 64-bit systems, a link to the Program Files folder. A typical path is /// C:\Program Files. - static String get ProgramFilesX64 => FOLDERID_ProgramFilesX64; + static String get ProgramFilesX64 => '{6D809377-6AF0-444b-8957-A3773F02200E}'; /// On 64-bit systems, a link to the 32-bit Program Files folder. A typical /// path is C:\Program Files (x86). On 32-bit systems, a link to the Common /// Program Files folder. - static String get ProgramFilesX86 => FOLDERID_ProgramFilesX86; + static String get ProgramFilesX86 => '{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}'; /// The file system directory that contains the user's program groups (which /// are themselves file system directories). - static String get Programs => FOLDERID_Programs; + static String get Programs => '{A77F5D77-2E2B-44C3-A6A2-ABA601054A51}'; /// The file system directory that contains files and folders that appear on /// the desktop for all users. A typical path is C:\Documents and Settings\All /// Users\Desktop. - static String get PublicDesktop => FOLDERID_PublicDesktop; + static String get PublicDesktop => '{C4AA340D-F20F-4863-AFEF-F87EF2E6BA25}'; /// The file system directory that contains documents that are common to all /// users. A typical path is C:\Documents and Settings\All Users\Documents. - static String get PublicDocuments => FOLDERID_PublicDocuments; + static String get PublicDocuments => '{ED4824AF-DCE4-45A8-81E2-FC7965083634}'; /// The file system directory that serves as a repository for music files /// common to all users. A typical path is C:\Documents and Settings\All /// Users\Documents\My Music. - static String get PublicMusic => FOLDERID_PublicMusic; + static String get PublicMusic => '{3214FAB5-9757-4298-BB61-92A9DEAA44FF}'; /// The file system directory that serves as a repository for image files /// common to all users. A typical path is C:\Documents and Settings\All /// Users\Documents\My Pictures. - static String get PublicPictures => FOLDERID_PublicPictures; + static String get PublicPictures => '{B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5}'; /// The file system directory that serves as a repository for video files /// common to all users. A typical path is C:\Documents and Settings\All /// Users\Documents\My Videos. - static String get PublicVideos => FOLDERID_PublicVideos; + static String get PublicVideos => '{2400183A-6185-49FB-A2D8-4A392A602BA3}'; /// The file system directory that contains shortcuts to the user's most /// recently used documents. A typical path is C:\Documents and /// Settings\username\My Recent Documents. - static String get Recent => FOLDERID_Recent; + static String get Recent => '{AE50C081-EBD2-438A-8655-8A092E34987A}'; /// The virtual folder that contains the objects in the user's Recycle Bin. - static String get RecycleBinFolder => FOLDERID_RecycleBinFolder; + static String get RecycleBinFolder => + '{B7534046-3ECB-4C18-BE4E-64CD4CB7D6AC}'; /// The file system directory that contains resource data. A typical path is /// C:\Windows\Resources. - static String get ResourceDir => FOLDERID_ResourceDir; + static String get ResourceDir => '{8AD10C31-2ADB-4296-A8F7-E4701232C972}'; /// The file system directory that serves as a common repository for /// application-specific data. A typical path is C:\Documents and /// Settings\username\Application Data. - static String get RoamingAppData => FOLDERID_RoamingAppData; + static String get RoamingAppData => '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}'; /// The file system directory that contains Send To menu items. A typical path /// is C:\Documents and Settings\username\SendTo. - static String get SendTo => FOLDERID_SendTo; + static String get SendTo => '{8983036C-27C0-404B-8F08-102D10DCFD74}'; /// The file system directory that contains Start menu items. A typical path /// is C:\Documents and Settings\username\Start Menu. - static String get StartMenu => FOLDERID_StartMenu; + static String get StartMenu => '{625B53C3-AB48-4EC1-BA1F-A1EF4146FC19}'; /// The file system directory that corresponds to the user's Startup program /// group. The system starts these programs whenever the associated user logs /// on. A typical path is C:\Documents and Settings\username\Start /// Menu\Programs\Startup. - static String get Startup => FOLDERID_Startup; + static String get Startup => '{B97D20BB-F46A-4C97-BA10-5E3608430854}'; /// The Windows System folder. A typical path is C:\Windows\System32. - static String get System => FOLDERID_System; + static String get System => '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}'; /// The 32-bit Windows System folder. On 32-bit systems, this is typically /// C:\Windows\system32. On 64-bit systems, this is typically /// C:\Windows\syswow64. - static String get SystemX86 => FOLDERID_SystemX86; + static String get SystemX86 => '{D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27}'; /// The file system directory that serves as a common repository for document /// templates. A typical path is C:\Documents and Settings\username\Templates. - static String get Templates => FOLDERID_Templates; + static String get Templates => '{A63293E8-664E-48DB-A079-DF759E0509F7}'; /// The file system directory that serves as a common repository for video /// files. A typical path is C:\Documents and Settings\username\My /// Documents\My Videos. - static String get Videos => FOLDERID_Videos; + static String get Videos => '{18989B1D-99B5-455B-841C-AB7C74E4DDFC}'; /// The Windows directory or SYSROOT. This corresponds to the %windir% or /// %SYSTEMROOT% environment variables. A typical path is C:\Windows. - static String get Windows => FOLDERID_Windows; + static String get Windows => '{F38BF404-1D43-42F2-9305-67DE0B28FC23}'; } diff --git a/packages/path_provider/path_provider_windows/lib/src/guid.dart b/packages/path_provider/path_provider_windows/lib/src/guid.dart new file mode 100644 index 0000000000000..84daffe6bed7f --- /dev/null +++ b/packages/path_provider/path_provider_windows/lib/src/guid.dart @@ -0,0 +1,51 @@ +// Copyright 2013 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:ffi'; +import 'dart:typed_data'; + +/// Representation of the Win32 GUID struct. +// For the layout of this struct, see +// https://learn.microsoft.com/windows/win32/api/guiddef/ns-guiddef-guid +@Packed(4) +base class GUID extends Struct { + /// Native Data1 field. + @Uint32() + external int data1; + + /// Native Data2 field. + @Uint16() + external int data2; + + /// Native Data3 field. + @Uint16() + external int data3; + + /// Native Data4 field. + // This should be an eight-element byte array, but there's no such annotation. + @Uint64() + external int data4; + + /// Parses a GUID string, with optional enclosing "{}"s and optional "-"s, + /// into data. + void parse(String guid) { + final String hexOnly = guid.replaceAll(RegExp(r'[{}-]'), ''); + if (hexOnly.length != 32) { + throw ArgumentError.value(guid, 'guid', 'Invalid GUID string'); + } + final ByteData bytes = ByteData(16); + for (int i = 0; i < 16; ++i) { + bytes.setUint8( + i, int.parse(hexOnly.substring(i * 2, i * 2 + 2), radix: 16)); + } + data1 = bytes.getInt32(0); + data2 = bytes.getInt16(4); + data3 = bytes.getInt16(6); + // [bytes] is big endian, but the host is little endian, so a default + // big-endian read would reverse the bytes. Since data4 is supposed to be + // a byte array, the order should be preserved, so do a little-endian read. + // https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding + data4 = bytes.getInt64(8, Endian.little); + } +} diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index 2faa599a53416..50f010ba56f20 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -7,11 +7,13 @@ import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart' show visibleForTesting; +import 'package:flutter/services.dart'; import 'package:path/path.dart' as path; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; -import 'package:win32/win32.dart'; import 'folders.dart'; +import 'guid.dart'; +import 'win32_wrappers.dart'; /// Constant for en-US language used in VersionInfo keys. @visibleForTesting @@ -35,7 +37,7 @@ class VersionInfoQuerier { /// language and encoding, or null if there is no such entry, /// or if versionInfo is null. /// - /// See https://docs.microsoft.com/en-us/windows/win32/menurc/versioninfo-resource + /// See https://docs.microsoft.com/windows/win32/menurc/versioninfo-resource /// for list of possible language and encoding values. String? getStringValue( Pointer? versionInfo, @@ -49,7 +51,7 @@ class VersionInfoQuerier { return null; } final Pointer keyPath = - TEXT('\\StringFileInfo\\$language$encoding\\$key'); + '\\StringFileInfo\\$language$encoding\\$key'.toNativeUtf16(); final Pointer length = calloc(); final Pointer> valueAddress = calloc>(); try { @@ -89,7 +91,7 @@ class PathProviderWindows extends PathProviderPlatform { if (length == 0) { final int error = GetLastError(); - throw WindowsException(error); + throw _createWin32Exception(error); } else { path = buffer.toDartString(); @@ -134,7 +136,7 @@ class PathProviderWindows extends PathProviderPlatform { /// [WindowsKnownFolder]. Future getPath(String folderID) { final Pointer> pathPtrPtr = calloc>(); - final Pointer knownFolderID = calloc()..ref.setGUID(folderID); + final Pointer knownFolderID = calloc()..ref.parse(folderID); try { final int hr = SHGetKnownFolderPath( @@ -146,7 +148,7 @@ class PathProviderWindows extends PathProviderPlatform { if (FAILED(hr)) { if (hr == E_INVALIDARG || hr == E_FAIL) { - throw WindowsException(hr); + throw _createWin32Exception(hr); } return Future.value(); } @@ -179,7 +181,8 @@ class PathProviderWindows extends PathProviderPlatform { String? companyName; String? productName; - final Pointer moduleNameBuffer = wsalloc(MAX_PATH + 1); + final Pointer moduleNameBuffer = + calloc(MAX_PATH + 1).cast(); final Pointer unused = calloc(); Pointer? infoBuffer; try { @@ -188,7 +191,7 @@ class PathProviderWindows extends PathProviderPlatform { GetModuleFileName(0, moduleNameBuffer, MAX_PATH); if (moduleNameLength == 0) { final int error = GetLastError(); - throw WindowsException(error); + throw _createWin32Exception(error); } // From that, load the VERSIONINFO resource @@ -223,7 +226,7 @@ class PathProviderWindows extends PathProviderPlatform { } /// Makes [rawString] safe as a directory component. See - /// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions + /// https://docs.microsoft.com/windows/win32/fileio/naming-a-file#naming-conventions /// /// If after sanitizing the string is empty, returns null. String? _sanitizedDirectoryName(String? rawString) { @@ -263,3 +266,15 @@ class PathProviderWindows extends PathProviderPlatform { return directory.path; } } + +Exception _createWin32Exception(int errorCode) { + return PlatformException( + code: 'Win32 Error', + // TODO(stuartmorgan): Consider getting the system error message via + // FormatMessage if it turns out to be necessary for debugging issues. + // Plugin-client-level usability isn't a major consideration since per + // https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#platform-exception-handling + // any case that comes up in practice should be handled and returned + // via a plugin-specific exception, not this fallback. + message: 'Error code 0x${errorCode.toRadixString(16)}'); +} diff --git a/packages/path_provider/path_provider_windows/lib/src/win32_wrappers.dart b/packages/path_provider/path_provider_windows/lib/src/win32_wrappers.dart new file mode 100644 index 0000000000000..a39488eb0a084 --- /dev/null +++ b/packages/path_provider/path_provider_windows/lib/src/win32_wrappers.dart @@ -0,0 +1,112 @@ +// Copyright 2013 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. + +// The types and functions here correspond directly to corresponding Windows +// types and functions, so the Windows docs are the definitive source of +// documentation. +// ignore_for_file: public_member_api_docs + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; + +import 'guid.dart'; + +typedef BOOL = Int32; +typedef BYTE = Uint8; +typedef DWORD = Uint32; +typedef UINT = Uint32; +typedef HANDLE = IntPtr; +typedef HMODULE = HANDLE; +typedef HRESULT = Int32; +typedef LPCVOID = Pointer; +typedef LPCWSTR = Pointer; +typedef LPDWORD = Pointer; +typedef LPWSTR = Pointer; +typedef LPVOID = Pointer; +typedef PUINT = Pointer; +typedef PWSTR = Pointer>; +typedef WCHAR = Uint16; + +const int NULL = 0; + +// https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry +const int MAX_PATH = 260; + +// https://learn.microsoft.com/windows/win32/seccrypto/common-hresult-values +// ignore: non_constant_identifier_names +final int E_FAIL = 0x80004005.toSigned(32); +// ignore: non_constant_identifier_names +final int E_INVALIDARG = 0x80070057.toSigned(32); + +// https://learn.microsoft.com/windows/win32/api/winerror/nf-winerror-failed#remarks +// ignore: non_constant_identifier_names +bool FAILED(int hr) => hr < 0; + +// https://learn.microsoft.com/windows/win32/api/shlobj_core/ne-shlobj_core-known_folder_flag +const int KF_FLAG_DEFAULT = 0x00000000; + +final DynamicLibrary _dllKernel32 = DynamicLibrary.open('kernel32.dll'); +final DynamicLibrary _dllVersion = DynamicLibrary.open('version.dll'); +final DynamicLibrary _dllShell32 = DynamicLibrary.open('shell32.dll'); + +// https://learn.microsoft.com/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath +typedef _FFITypeSHGetKnownFolderPath = HRESULT Function( + Pointer, DWORD, HANDLE, PWSTR); +typedef FFITypeSHGetKnownFolderPathDart = int Function( + Pointer, int, int, Pointer>); +// ignore: non_constant_identifier_names +final FFITypeSHGetKnownFolderPathDart SHGetKnownFolderPath = + _dllShell32.lookupFunction<_FFITypeSHGetKnownFolderPath, + FFITypeSHGetKnownFolderPathDart>('SHGetKnownFolderPath'); + +// https://learn.microsoft.com/windows/win32/api/winver/nf-winver-getfileversioninfow +typedef _FFITypeGetFileVersionInfoW = BOOL Function( + LPCWSTR, DWORD, DWORD, LPVOID); +typedef FFITypeGetFileVersionInfoW = int Function( + Pointer, int, int, Pointer); +// ignore: non_constant_identifier_names +final FFITypeGetFileVersionInfoW GetFileVersionInfo = _dllVersion + .lookupFunction<_FFITypeGetFileVersionInfoW, FFITypeGetFileVersionInfoW>( + 'GetFileVersionInfoW'); + +// https://learn.microsoft.com/windows/win32/api/winver/nf-winver-getfileversioninfosizew +typedef _FFITypeGetFileVersionInfoSizeW = DWORD Function(LPCWSTR, LPDWORD); +typedef FFITypeGetFileVersionInfoSizeW = int Function( + Pointer, Pointer); +// ignore: non_constant_identifier_names +final FFITypeGetFileVersionInfoSizeW GetFileVersionInfoSize = + _dllVersion.lookupFunction<_FFITypeGetFileVersionInfoSizeW, + FFITypeGetFileVersionInfoSizeW>('GetFileVersionInfoSizeW'); + +// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror +typedef _FFITypeGetLastError = DWORD Function(); +typedef FFITypeGetLastError = int Function(); +// ignore: non_constant_identifier_names +final FFITypeGetLastError GetLastError = _dllKernel32 + .lookupFunction<_FFITypeGetLastError, FFITypeGetLastError>('GetLastError'); + +// https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew +typedef _FFITypeGetModuleFileNameW = DWORD Function(HMODULE, LPWSTR, DWORD); +typedef FFITypeGetModuleFileNameW = int Function(int, Pointer, int); +// ignore: non_constant_identifier_names +final FFITypeGetModuleFileNameW GetModuleFileName = _dllKernel32.lookupFunction< + _FFITypeGetModuleFileNameW, + FFITypeGetModuleFileNameW>('GetModuleFileNameW'); + +// https://learn.microsoft.com/windows/win32/api/winver/nf-winver-verqueryvaluew +typedef _FFITypeVerQueryValueW = BOOL Function(LPCVOID, LPCWSTR, LPVOID, PUINT); +typedef FFITypeVerQueryValueW = int Function( + Pointer, Pointer, Pointer, Pointer); +// ignore: non_constant_identifier_names +final FFITypeVerQueryValueW VerQueryValue = + _dllVersion.lookupFunction<_FFITypeVerQueryValueW, FFITypeVerQueryValueW>( + 'VerQueryValueW'); + +// https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-gettemppathw +typedef _FFITypeGetTempPathW = DWORD Function(DWORD, LPWSTR); +typedef FFITypeGetTempPathW = int Function(int, Pointer); +// ignore: non_constant_identifier_names +final FFITypeGetTempPathW GetTempPath = _dllKernel32 + .lookupFunction<_FFITypeGetTempPathW, FFITypeGetTempPathW>('GetTempPathW'); diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index c3211cf3c474a..cb84e14accc64 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.2.1 +version: 2.3.0 environment: sdk: ^3.2.0 @@ -21,7 +21,6 @@ dependencies: sdk: flutter path: ^1.8.0 path_provider_platform_interface: ^2.1.0 - win32: ">=2.1.0 <6.0.0" dev_dependencies: flutter_test: diff --git a/packages/path_provider/path_provider_windows/test/guid_test.dart b/packages/path_provider/path_provider_windows/test/guid_test.dart new file mode 100644 index 0000000000000..561ad3b87d620 --- /dev/null +++ b/packages/path_provider/path_provider_windows/test/guid_test.dart @@ -0,0 +1,63 @@ +// Copyright 2013 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:ffi'; +import 'dart:typed_data'; + +import 'package:ffi/ffi.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider_windows/src/guid.dart'; + +void main() { + test('has correct byte representation', () async { + final Pointer guid = calloc() + ..ref.parse('{00112233-4455-6677-8899-aabbccddeeff}'); + final ByteData data = ByteData(16) + ..setInt32(0, guid.ref.data1, Endian.little) + ..setInt16(4, guid.ref.data2, Endian.little) + ..setInt16(6, guid.ref.data3, Endian.little) + ..setInt64(8, guid.ref.data4, Endian.little); + expect(data.getUint8(0), 0x33); + expect(data.getUint8(1), 0x22); + expect(data.getUint8(2), 0x11); + expect(data.getUint8(3), 0x00); + expect(data.getUint8(4), 0x55); + expect(data.getUint8(5), 0x44); + expect(data.getUint8(6), 0x77); + expect(data.getUint8(7), 0x66); + expect(data.getUint8(8), 0x88); + expect(data.getUint8(9), 0x99); + expect(data.getUint8(10), 0xAA); + expect(data.getUint8(11), 0xBB); + expect(data.getUint8(12), 0xCC); + expect(data.getUint8(13), 0xDD); + expect(data.getUint8(14), 0xEE); + expect(data.getUint8(15), 0xFF); + + calloc.free(guid); + }); + + test('handles alternate forms', () async { + final Pointer guid1 = calloc() + ..ref.parse('{00112233-4455-6677-8899-aabbccddeeff}'); + final Pointer guid2 = calloc() + ..ref.parse('00112233445566778899AABBCCDDEEFF'); + + expect(guid1.ref.data1, guid2.ref.data1); + expect(guid1.ref.data2, guid2.ref.data2); + expect(guid1.ref.data3, guid2.ref.data3); + expect(guid1.ref.data4, guid2.ref.data4); + + calloc.free(guid1); + calloc.free(guid2); + }); + + test('throws for bad data', () async { + final Pointer guid = calloc(); + + expect(() => guid.ref.parse('{00112233-4455-6677-88'), throwsArgumentError); + + calloc.free(guid); + }); +} diff --git a/script/configs/allowed_unpinned_deps.yaml b/script/configs/allowed_unpinned_deps.yaml index 974385ac14651..fa23bb48c9103 100644 --- a/script/configs/allowed_unpinned_deps.yaml +++ b/script/configs/allowed_unpinned_deps.yaml @@ -13,7 +13,6 @@ # cautious about adding to this list. - build_verify - google_maps -- win32 ## Allowed by default