mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-09 12:46:47 +02:00
[Peek] Open file in Read only (#25945)
* Only open FilStream in read-only mode; Release propertyStore handle after getting the file properties
(cherry picked from commit 3b1481da2c)
* Update calls to PropertyStoreHelper
* Add disposable property store
* Make GetPropertyStoreFromPath return Disposable property store
* correct typo
* correct typo
* Remove nullable in DisposablePropertyStore
* Add property getters
* Remove usued method
* Correct typo
* Correct typo again...
* Update description
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Peek.Common.Models;
|
||||||
|
|
||||||
|
namespace Peek.Common.Extensions
|
||||||
|
{
|
||||||
|
public sealed class DisposablePropertyStore : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IPropertyStore _propertyStore;
|
||||||
|
|
||||||
|
public DisposablePropertyStore(IPropertyStore propertyStore)
|
||||||
|
{
|
||||||
|
_propertyStore = propertyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetValue(ref PropertyKey key, out PropVariant pv)
|
||||||
|
{
|
||||||
|
_propertyStore!.GetValue(ref key, out pv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Marshal.ReleaseComObject(_propertyStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,9 +21,8 @@ namespace Peek.Common.Extensions
|
|||||||
{
|
{
|
||||||
Size? size = null;
|
Size? size = null;
|
||||||
|
|
||||||
var propertyStore = item.PropertyStore;
|
var width = item.Width;
|
||||||
var width = propertyStore.TryGetUInt(PropertyKey.ImageHorizontalSize);
|
var height = item.Height;
|
||||||
var height = propertyStore.TryGetUInt(PropertyKey.ImageVerticalSize);
|
|
||||||
|
|
||||||
if (width != null && height != null)
|
if (width != null && height != null)
|
||||||
{
|
{
|
||||||
@@ -36,8 +35,7 @@ namespace Peek.Common.Extensions
|
|||||||
public static Size? GetSvgSize(this IFileSystemItem item)
|
public static Size? GetSvgSize(this IFileSystemItem item)
|
||||||
{
|
{
|
||||||
Size? size = null;
|
Size? size = null;
|
||||||
|
using (FileStream stream = new FileStream(item.Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
|
||||||
using (FileStream stream = System.IO.File.OpenRead(item.Path))
|
|
||||||
{
|
{
|
||||||
XmlReaderSettings settings = new XmlReaderSettings();
|
XmlReaderSettings settings = new XmlReaderSettings();
|
||||||
settings.Async = true;
|
settings.Async = true;
|
||||||
@@ -95,8 +93,7 @@ namespace Peek.Common.Extensions
|
|||||||
sizeInBytes = (ulong)folder.Size;
|
sizeInBytes = (ulong)folder.Size;
|
||||||
break;
|
break;
|
||||||
case FileItem _:
|
case FileItem _:
|
||||||
var propertyStore = item.PropertyStore;
|
sizeInBytes = item.FileSizeBytes;
|
||||||
sizeInBytes = propertyStore.TryGetULong(PropertyKey.FileSizeBytes) ?? 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,8 +114,7 @@ namespace Peek.Common.Extensions
|
|||||||
contentType = storageFolder.DisplayType;
|
contentType = storageFolder.DisplayType;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
var propertyStore = item.PropertyStore;
|
contentType = item.FileType;
|
||||||
contentType = propertyStore.TryGetString(PropertyKey.FileType) ?? string.Empty;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Peek.Common.Extensions
|
|||||||
/// <param name="propertyStore">The property store</param>
|
/// <param name="propertyStore">The property store</param>
|
||||||
/// <param name="key">The pkey</param>
|
/// <param name="key">The pkey</param>
|
||||||
/// <returns>The uint value</returns>
|
/// <returns>The uint value</returns>
|
||||||
public static uint? TryGetUInt(this IPropertyStore propertyStore, PropertyKey key)
|
public static uint? TryGetUInt(this DisposablePropertyStore propertyStore, PropertyKey key)
|
||||||
{
|
{
|
||||||
if (propertyStore == null)
|
if (propertyStore == null)
|
||||||
{
|
{
|
||||||
@@ -54,7 +54,7 @@ namespace Peek.Common.Extensions
|
|||||||
/// <param name="propertyStore">The property store</param>
|
/// <param name="propertyStore">The property store</param>
|
||||||
/// <param name="key">the pkey</param>
|
/// <param name="key">the pkey</param>
|
||||||
/// <returns>the ulong value</returns>
|
/// <returns>the ulong value</returns>
|
||||||
public static ulong? TryGetULong(this IPropertyStore propertyStore, PropertyKey key)
|
public static ulong? TryGetULong(this DisposablePropertyStore propertyStore, PropertyKey key)
|
||||||
{
|
{
|
||||||
if (propertyStore == null)
|
if (propertyStore == null)
|
||||||
{
|
{
|
||||||
@@ -89,7 +89,7 @@ namespace Peek.Common.Extensions
|
|||||||
/// <param name="propertyStore">The property store</param>
|
/// <param name="propertyStore">The property store</param>
|
||||||
/// <param name="key">The pkey</param>
|
/// <param name="key">The pkey</param>
|
||||||
/// <returns>The string value</returns>
|
/// <returns>The string value</returns>
|
||||||
public static string? TryGetString(this IPropertyStore propertyStore, PropertyKey key)
|
public static string? TryGetString(this DisposablePropertyStore propertyStore, PropertyKey key)
|
||||||
{
|
{
|
||||||
if (propertyStore == null)
|
if (propertyStore == null)
|
||||||
{
|
{
|
||||||
@@ -116,46 +116,5 @@ namespace Peek.Common.Extensions
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Helper method that retrieves an array of string values from the given property store.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyStore">The property store</param>
|
|
||||||
/// <param name="key">The pkey</param>
|
|
||||||
/// <returns>The array of string values</returns>
|
|
||||||
public static string[]? TryGetStringArray(this IPropertyStore propertyStore, PropertyKey key)
|
|
||||||
{
|
|
||||||
if (propertyStore == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PropVariant propVar;
|
|
||||||
propertyStore.GetValue(ref key, out propVar);
|
|
||||||
|
|
||||||
List<string>? values = null;
|
|
||||||
|
|
||||||
if ((VarEnum)propVar.Vt == (VarEnum.VT_LPWSTR | VarEnum.VT_VECTOR))
|
|
||||||
{
|
|
||||||
values = new List<string>();
|
|
||||||
for (int elementIndex = 0; elementIndex < propVar.Calpwstr.CElems; elementIndex++)
|
|
||||||
{
|
|
||||||
var stringVal = Marshal.PtrToStringUni(Marshal.ReadIntPtr(propVar.Calpwstr.PElems, elementIndex));
|
|
||||||
if (stringVal != null)
|
|
||||||
{
|
|
||||||
values.Add(stringVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return values?.ToArray();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Peek.Common.Extensions;
|
||||||
using Peek.Common.Models;
|
using Peek.Common.Models;
|
||||||
using Windows.Win32.UI.Shell.PropertiesSystem;
|
using Windows.Win32.UI.Shell.PropertiesSystem;
|
||||||
|
|
||||||
@@ -14,12 +14,48 @@ namespace Peek.Common.Helpers
|
|||||||
public static partial class PropertyStoreHelper
|
public static partial class PropertyStoreHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a IPropertyStore interface from the given path.
|
/// Gets a uint type value from PropertyStore from the given item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file/folder path</param>
|
||||||
|
/// <param name="key">The property key</param>
|
||||||
|
/// <returns>a nullable uint</returns>
|
||||||
|
public static uint? TryGetUintProperty(string path, PropertyKey key)
|
||||||
|
{
|
||||||
|
using DisposablePropertyStore propertyStore = GetPropertyStoreFromPath(path);
|
||||||
|
return propertyStore.TryGetUInt(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a ulong type value from PropertyStore from the given item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file/folder path</param>
|
||||||
|
/// <param name="key">The property key</param>
|
||||||
|
/// <returns>a nullable ulong</returns>
|
||||||
|
public static ulong? TryGetUlongProperty(string path, PropertyKey key)
|
||||||
|
{
|
||||||
|
using DisposablePropertyStore propertyStore = GetPropertyStoreFromPath(path);
|
||||||
|
return propertyStore.TryGetULong(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string type value from PropertyStore from the given item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file/folder path</param>
|
||||||
|
/// <param name="key">The property key</param>
|
||||||
|
/// <returns>a nullable string</returns>
|
||||||
|
public static string? TryGetStringProperty(string path, PropertyKey key)
|
||||||
|
{
|
||||||
|
using DisposablePropertyStore propertyStore = GetPropertyStoreFromPath(path);
|
||||||
|
return propertyStore.TryGetString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a IPropertyStore interface (wrapped in DisposablePropertyStore) from the given path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The file/folder path</param>
|
/// <param name="path">The file/folder path</param>
|
||||||
/// <param name="flags">The property store flags</param>
|
/// <param name="flags">The property store flags</param>
|
||||||
/// <returns>an IPropertyStroe interface</returns>
|
/// <returns>an IPropertyStroe interface</returns>
|
||||||
public static IPropertyStore GetPropertyStoreFromPath(string path, GETPROPERTYSTOREFLAGS flags = GETPROPERTYSTOREFLAGS.GPS_EXTRINSICPROPERTIES)
|
private static DisposablePropertyStore GetPropertyStoreFromPath(string path, GETPROPERTYSTOREFLAGS flags = GETPROPERTYSTOREFLAGS.GPS_EXTRINSICPROPERTIES)
|
||||||
{
|
{
|
||||||
IShellItem2? shellItem2 = null;
|
IShellItem2? shellItem2 = null;
|
||||||
IntPtr ppPropertyStore = IntPtr.Zero;
|
IntPtr ppPropertyStore = IntPtr.Zero;
|
||||||
@@ -40,7 +76,7 @@ namespace Peek.Common.Helpers
|
|||||||
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "GetPropertyStore returned hresult={0}", hr));
|
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "GetPropertyStore returned hresult={0}", hr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (IPropertyStore)Marshal.GetObjectForIUnknown(ppPropertyStore);
|
return new DisposablePropertyStore((IPropertyStore)Marshal.GetObjectForIUnknown(ppPropertyStore));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Peek.Common.Extensions;
|
||||||
using Peek.Common.Helpers;
|
using Peek.Common.Helpers;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
|
||||||
@@ -15,18 +17,13 @@ namespace Peek.Common.Models
|
|||||||
{
|
{
|
||||||
private StorageFile? storageFile;
|
private StorageFile? storageFile;
|
||||||
|
|
||||||
private Lazy<IPropertyStore> _propertyStore;
|
|
||||||
|
|
||||||
public FileItem(string path)
|
public FileItem(string path)
|
||||||
{
|
{
|
||||||
Path = path;
|
Path = path;
|
||||||
_propertyStore = new(() => PropertyStoreHelper.GetPropertyStoreFromPath(Path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Path { get; init; }
|
public string Path { get; init; }
|
||||||
|
|
||||||
public IPropertyStore PropertyStore => _propertyStore.Value;
|
|
||||||
|
|
||||||
public async Task<IStorageItem?> GetStorageItemAsync()
|
public async Task<IStorageItem?> GetStorageItemAsync()
|
||||||
{
|
{
|
||||||
return await GetStorageFileAsync();
|
return await GetStorageFileAsync();
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Peek.Common.Extensions;
|
||||||
using Peek.Common.Helpers;
|
using Peek.Common.Helpers;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
|
||||||
@@ -15,18 +17,13 @@ namespace Peek.Common.Models
|
|||||||
{
|
{
|
||||||
private StorageFolder? storageFolder;
|
private StorageFolder? storageFolder;
|
||||||
|
|
||||||
private Lazy<IPropertyStore> _propertyStore;
|
|
||||||
|
|
||||||
public FolderItem(string path)
|
public FolderItem(string path)
|
||||||
{
|
{
|
||||||
Path = path;
|
Path = path;
|
||||||
_propertyStore = new(() => PropertyStoreHelper.GetPropertyStoreFromPath(Path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Path { get; init; }
|
public string Path { get; init; }
|
||||||
|
|
||||||
public IPropertyStore PropertyStore => _propertyStore.Value;
|
|
||||||
|
|
||||||
public async Task<IStorageItem?> GetStorageItemAsync()
|
public async Task<IStorageItem?> GetStorageItemAsync()
|
||||||
{
|
{
|
||||||
return await GetStorageFolderAsync();
|
return await GetStorageFolderAsync();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Peek.Common.Extensions;
|
||||||
using Peek.Common.Helpers;
|
using Peek.Common.Helpers;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
|
||||||
@@ -22,7 +23,13 @@ namespace Peek.Common.Models
|
|||||||
|
|
||||||
public string Path { get; init; }
|
public string Path { get; init; }
|
||||||
|
|
||||||
public IPropertyStore PropertyStore { get; }
|
public uint? Width => PropertyStoreHelper.TryGetUintProperty(Path, PropertyKey.ImageHorizontalSize);
|
||||||
|
|
||||||
|
public uint? Height => PropertyStoreHelper.TryGetUintProperty(Path, PropertyKey.ImageVerticalSize);
|
||||||
|
|
||||||
|
public ulong FileSizeBytes => PropertyStoreHelper.TryGetUlongProperty(Path, PropertyKey.FileSizeBytes) ?? 0;
|
||||||
|
|
||||||
|
public string FileType => PropertyStoreHelper.TryGetStringProperty(Path, PropertyKey.FileType) ?? string.Empty;
|
||||||
|
|
||||||
public Task<IStorageItem?> GetStorageItemAsync();
|
public Task<IStorageItem?> GetStorageItemAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ namespace Peek.FilePreviewer.Previewers
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
using FileStream stream = File.OpenRead(Item.Path);
|
using FileStream stream = ReadHelper.OpenReadOnly(Item.Path);
|
||||||
|
|
||||||
await Dispatcher.RunOnUiThread(async () =>
|
await Dispatcher.RunOnUiThread(async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ namespace Peek.FilePreviewer.Previewers
|
|||||||
{
|
{
|
||||||
public static async Task<string> Read(string path)
|
public static async Task<string> Read(string path)
|
||||||
{
|
{
|
||||||
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
|
using var fs = OpenReadOnly(path);
|
||||||
using var sr = new StreamReader(fs, Encoding.UTF8);
|
using var sr = new StreamReader(fs, Encoding.UTF8);
|
||||||
|
|
||||||
string content = await sr.ReadToEndAsync();
|
string content = await sr.ReadToEndAsync();
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FileStream OpenReadOnly(string path)
|
||||||
|
{
|
||||||
|
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user