microsoft / microsoft/WindowsAppSDK
StorageDevice.FromId(id) gives 'Access Denied Exception' in a OOP background task in WinUI3 - Desktop
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 4.7k
- Forks
- 471
- Avg merge
- 3d 13h
- Merged PRs (30d)
- 28
Description
### Describe the bug
I am porting a UWP/DesktopBridge app to WinUI - Desktop. The app registers a `DeviceWatcher` task to detect inserts and ejects of USB storage devices.
In the UWP app the task is an in-process task; in the WinUI app it is (must be) a OOP task.
The task runs well but there is a `Access denied` exception when the task is informed about a USB device being inserted and then calls `StorageDevice.FromId(id)`. The call is there in order to get a `StorageFolder` and from there to extract the `Volume Label` and `Drive Letter` of the MSC device.
The app is SyncFolder, which is a folder sync/copy tool for users, and the `Volume Label` and `Drive Letter` information is needed in order to find out whether the app must inform the user that a possible candidate storage device is being inserted for a given sync/backup task. This would be necessary when the user is using a set of rotating backup disks. Volume Label (and to a lesser extend Drive Letter) would then be the common name for all disks in the set.
The exception happens in the call to `Windows.Devices.Portable.StorageDevice.FromId()`. The code is actually quite simple:
```
async Task> GetAvailableMSCStorageDevicesAsync()
{
var devices = new List();
var portableStorageDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Devices.Enumeration.DeviceClass.PortableStorageDevice);
ConditionalFileLogger.Log($"PortableStorageDevicesMonitor - GetAvailableStorageDevicesAsync: found {portableStorageDevices.Count} portable devices");
foreach (var d in portableStorageDevices)
{
int step = 0;
try
{
step = 1;
var props = d.Properties;
ConditionalFileLogger.Log($"PortableStorageDevicesMonitor - GetAvailableStorageDevicesAsync: get storage folder of {d.Name}, {d.Id}");
step = 2;
var storageFolder = Windows.Devices.Portable.StorageDevice.FromId(d.Id);
if (storageFolder != null &&
!String.IsNullOrEmpty(storageFolder.Path))
{
step = 3;
ConditionalFileLogger.Log($"PortableStorageDevicesMonitor - RefreshPortableStorageDevicesAsync: add {{d.Name}} ({storageFolder.Path}) to list");
string driveLetter;
string volumeLabel = StorageDeviceExt.GetVolumeLabelAndDriveLetter(storageFolder.DisplayName, out driveLetter);
devices.Add(new StorageDeviceExt.StorageDeviceInfo()
{
DeviceId = d.Id,
DriveType = System.IO.DriveType.Removable,
VolumeLabel = volumeLabel,
DriveLetter = driveLetter
});
}
}
catch (Exception e)
{
ConditionalFileLogger.Log($"StorageDeviceHelper - RefreshPortableStorageDevicesAsync exception 1, step {step} for {d.Name}: {e.Message}");
Analytics.TrackEvent("PortableStorageDevicesMonitor-Exception", new Dictionary
{
{ "Exception", $"GetAvailableStorageDevicesAsync: {e.Message}" }
});
}
}
ConditionalFileLogger.Log($"PortableStorageDevicesMonitor - GetAvailableStorageDevicesAsync: found {devices.Count} portable MSC storage devices");
return devices;
}
```
`ConditionalFileLogger` is my own implementation of a log service that outputs log events to a file.
`Analytics.TrackEvent(..)` is a call to ms appcenter to register the exception in appcenter.
The exception is: Access denied. (0x80070005 (E_ACCESSDENIED)) and is generated for every USB device for which the `FromId()` call is made.
The same call to the above `GetAvailableMSCStorageDevicesAsync()` method runs fine when invoked from within the WinUI app itself (i.e. not from the OOP WinRT process).
So, it seems that the app itself is granted all the rights to get a `StorageFolder` for a portable device but not the OOP `DeviceWatcher` task.
Is this intended behavior?
That would be strange/wrong because the same code in the UWP in-process DeviceWatcher runs without issues.
### Steps to reproduce the bug
Create a OOP DeviceWatcher task in a WinUI 3 Desktop app (packaged, using wap project).
Register the task.
Call `Windows.Devices.Portable.StorageDevice.FromId()`
### Expected behavior
_No response_
### Screenshots
_No response_
### NuGet package version
1.0.0
### Packaging type
Packaged (MSIX)
### Windows version
Windows 11 version 21H2 (22000)
### IDE
Visual Studio 2022
### Additional context
_No response_
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the packaged WinUI 3 Desktop OOP DeviceWatcher reproduction described in the issue, focusing on Windows.Devices.Portable.StorageDevice.FromId(). Compare the call from the OOP task with the same GetAvailableMSCStorageDevicesAsync() call from the app process. Done means establishing whether E_ACCESSDENIED is intended for OOP tasks and documenting or identifying the supported way to obtain the StorageFolder.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100