diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index ef1f5043a2b7..ea271681e63c 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety + +* Migrate to null safety + ## 0.0.4+4 * Update Flutter SDK constraint. 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 e1063957879e..856249036b62 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 @@ -22,20 +22,19 @@ import 'folders.dart'; class VersionInfoQuerier { /// Returns the value for [key] in [versionInfo]s English strings section, or /// null if there is no such entry, or if versionInfo is null. - getStringValue(Pointer versionInfo, key) { + getStringValue(Pointer? versionInfo, key) { if (versionInfo == null) { return null; } const kEnUsLanguageCode = '040904e4'; final keyPath = TEXT('\\StringFileInfo\\$kEnUsLanguageCode\\$key'); final length = allocate(); - final valueAddress = allocate(); + final valueAddress = allocate>(); try { if (VerQueryValue(versionInfo, keyPath, valueAddress, length) == 0) { return null; } - return Pointer.fromAddress(valueAddress.value) - .unpackString(length.value); + return valueAddress.value.unpackString(length.value); } finally { free(keyPath); free(length); @@ -54,7 +53,7 @@ class PathProviderWindows extends PathProviderPlatform { /// This is typically the same as the TMP environment variable. @override - Future getTemporaryPath() async { + Future getTemporaryPath() async { final buffer = allocate(count: MAX_PATH + 1).cast(); String path; @@ -88,7 +87,7 @@ class PathProviderWindows extends PathProviderPlatform { } @override - Future getApplicationSupportPath() async { + Future getApplicationSupportPath() async { final appDataRoot = await getPath(WindowsKnownFolder.RoamingAppData); final directory = Directory( path.join(appDataRoot, _getApplicationSpecificSubdirectory())); @@ -105,25 +104,23 @@ class PathProviderWindows extends PathProviderPlatform { } @override - Future getApplicationDocumentsPath() => + Future getApplicationDocumentsPath() => getPath(WindowsKnownFolder.Documents); @override - Future getDownloadsPath() => getPath(WindowsKnownFolder.Downloads); + Future getDownloadsPath() => getPath(WindowsKnownFolder.Downloads); /// Retrieve any known folder from Windows. /// /// folderID is a GUID that represents a specific known folder ID, drawn from /// [WindowsKnownFolder]. Future getPath(String folderID) { - final pathPtrPtr = allocate(); - Pointer pathPtr; + final pathPtrPtr = allocate>(); + final Pointer knownFolderID = calloc()..setGUID(folderID); try { - GUID knownFolderID = GUID.fromString(folderID); - final hr = SHGetKnownFolderPath( - knownFolderID.addressOf, // ignore: deprecated_member_use + knownFolderID, KF_FLAG_DEFAULT, NULL, pathPtrPtr, @@ -135,12 +132,11 @@ class PathProviderWindows extends PathProviderPlatform { } } - pathPtr = Pointer.fromAddress(pathPtrPtr.value); - final path = pathPtr.unpackString(MAX_PATH); + final path = pathPtrPtr.value.unpackString(MAX_PATH); return Future.value(path); } finally { - CoTaskMemFree(pathPtr.cast()); free(pathPtrPtr); + free(knownFolderID); } } @@ -155,13 +151,13 @@ class PathProviderWindows extends PathProviderPlatform { /// - If the product name isn't there, it will use the exe's filename (without /// extension). String _getApplicationSpecificSubdirectory() { - String companyName; - String productName; + String? companyName; + String? productName; final Pointer moduleNameBuffer = allocate(count: MAX_PATH + 1).cast(); final Pointer unused = allocate(); - Pointer infoBuffer; + Pointer? infoBuffer; try { // Get the module name. final moduleNameLength = GetModuleFileName(0, moduleNameBuffer, MAX_PATH); @@ -207,7 +203,7 @@ class PathProviderWindows extends PathProviderPlatform { /// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions /// /// If after sanitizing the string is empty, returns null. - String _sanitizedDirectoryName(String rawString) { + String? _sanitizedDirectoryName(String? rawString) { if (rawString == null) { return null; } diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart index 11a946542f26..1a0e84e8f0da 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart @@ -19,7 +19,7 @@ class PathProviderWindows extends PathProviderPlatform { } /// Stub; see comment on VersionInfoQuerier. - VersionInfoQuerier versionInfoQuerier; + VersionInfoQuerier versionInfoQuerier = VersionInfoQuerier(); /// Match PathProviderWindows so that the analyzer won't report invalid /// overrides if tests provide fake PathProviderWindows implementations. diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 62185f42e765..55c73c87ad19 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.0.4+4 +version: 0.1.0-nullsafety flutter: plugin: @@ -11,19 +11,19 @@ flutter: pluginClass: none dependencies: - path_provider_platform_interface: ^1.0.3 - meta: ^1.0.5 - path: ^1.6.4 + path_provider_platform_interface: ^2.0.0-nullsafety + meta: ^1.3.0-nullsafety.6 + path: ^1.8.0-nullsafety.3 flutter: sdk: flutter - ffi: ^0.1.3 - win32: ^1.7.1 + ffi: ^0.2.0-nullsafety.1 + win32: ^2.0.0-nullsafety.8 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.12.13+hotfix.4" diff --git a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart index 83ceea9cdf0c..989f3673ac63 100644 --- a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart +++ b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart @@ -13,7 +13,7 @@ class FakeVersionInfoQuerier implements VersionInfoQuerier { final Map responses; - getStringValue(Pointer versionInfo, key) => responses[key]; + getStringValue(Pointer? versionInfo, key) => responses[key]; } void main() { @@ -40,8 +40,11 @@ void main() { 'ProductName': 'Amazing App', }); final path = await pathProvider.getApplicationSupportPath(); - expect(path, endsWith(r'AppData\Roaming\A Company\Amazing App')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Roaming\A Company\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with missing company', () async { @@ -50,8 +53,11 @@ void main() { 'ProductName': 'Amazing App', }); final path = await pathProvider.getApplicationSupportPath(); - expect(path, endsWith(r'AppData\Roaming\Amazing App')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Roaming\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with problematic values', () async { @@ -61,12 +67,15 @@ void main() { 'ProductName': r'A"/Terrible\|App?*Name', }); final path = await pathProvider.getApplicationSupportPath(); - expect( - path, - endsWith(r'AppData\Roaming\' - r'A _Bad_ Company_ Name\' - r'A__Terrible__App__Name')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect( + path, + endsWith(r'AppData\Roaming\' + r'A _Bad_ Company_ Name\' + r'A__Terrible__App__Name')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with a completely invalid company', () async { @@ -76,8 +85,11 @@ void main() { 'ProductName': r'Amazing App', }); final path = await pathProvider.getApplicationSupportPath(); - expect(path, endsWith(r'AppData\Roaming\Amazing App')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Roaming\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with very long app name', () async {