FileOpenPicker on Xbox One : Removed in latest SDK ?

Clément Micard 21 Reputation points
2021-01-28T17:54:14.517+00:00

Hello ! This is a post to maybe report a bug, or just indicate that there is a problem with the latest UWP SDK.
When I target the latest verion of the SDK in my UWP, the FileOpenPicker works very well on PC, but on Xbox One it returns null when user select a file.
Is the FileOpenPicker removed from the latest SDK on Xbox ?

Universal Windows Platform (UWP)
0 comments No comments
{count} votes

Accepted answer
  1. Nico Zhu (Shanghai Wicresoft Co,.Ltd.) 12,851 Reputation points
    2021-01-29T02:05:21.483+00:00

    Hello @Clément Micard , Welcome to Micorosoft Q&A,

    Currently, there is no such description that FileOpenPicker has been obsolete within Xob platform.
    If you could reproduce this problem, please feel free post it with windows feed back hub app, and current workaround is modify the project 17763 as the Minimum build and select 1809 as Target build.


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


1 additional answer

Sort by: Most helpful
  1. Christopher Lee 111 Reputation points
    2021-04-07T03:56:04.95+00:00

    I'm seeing similar symptoms in the following environment:

    • JavaScript application
    • Minimum version 10.0.10240.0 (initial version released July 2015)
    • Target version 10.0.19041.0 (version 2004, May 2020 Update)
    • Multi-user application (manifest uap:SupportedUsers = multiple)

    The scenario is creating a picker using the Windows.Storage.Pickers.FileOpenPicker constructor (intended for single user applications) and then calling FileOpenPicker.PickSingleFileAsync or FileOpenPicker.PickMultipleFilesAsync. The picker appears to behave normally including while selecting a file, but there is a noticeable delay in user interface responsiveness after choosing a file, and the returned file is null. (Based on an experiment of deploying the "File picker provider sample" from the Universal Windows Platform (UWP) app samples modified to be a multi-user application, this might be the file picker basket throwing "Access is denied." (error code 0x80070005) when File Explorer calls Windows.Storage.Pickers.Provider.FileOpenPickerUI.AddFile.)

    I switched to creating a file picker for multi-user applications (using FileOpenPicker.CreateForUser), but calling FileOpenPicker.PickSingleFileAsync or FileOpenPicker.PickMultipleFilesAsync would result in the error "Invalid window handle." (error code 0x80070578).

    The workaround I settled on was catching that specific error code, then calling Windows.Storage.DownloadsFolder.CreateFolderForUserAsync with a made-up preset temporary folder name (and setting Windows.Storage.CreationCollisionOption.FailIfExists), and if that succeeded, then I immediately cleaned up that folder by calling StorageFolder.DeleteAsync. Regardless of whether the temporary folder was created or not, this prepares the file picker for the remaining running lifetime of the application, and you can retry calling the FileOpenPicker methods normally.

    Note that this workaround does leave behind a folder in the Downloads folder named after your application that your application cannot delete automatically; if its presence bothers you or your users, you can have the user open a folder picker to the parent folder (the Downloads folder) and then you can delete that child folder, preferably after verifying that the child folder is still empty.

    The DownloadsFolder workaround is implemented as the following; in Microsoft Visual Studio 2017, create a new JavaScript project using the "Blank App (Universal Windows)" template, set the minimum and target versions as described earlier, add <uap:SupportedUsers>multiple</uap:SupportedUsers> inside /Package/Properties to package.appxmanifest, and replace the contents of main.js with the following code:

       Windows.UI.WebUI.WebUIApplication.onactivated = Application_Activate_FilePicker;  
         
       function Application_Activate_FilePicker(eventDetails)  
       {  
       var sender = eventDetails.target;  
       var activationEventArguments = eventDetails.detail[0];  
         
       var user = activationEventArguments.user;  
         
       var openPicker = BuildFileOpenPickerForUser(user);  
       openPicker.pickSingleFileAsync().then(BindFunctionToContextOnce(Application_Activate_FilePicker_FilePicked, user), BindFunctionToContextOnce(Application_Activate_FilePicker_FilePickerFailed, user));  
       }  
         
       function Application_Activate_FilePicker_FilePicked(file)  
       {  
       var user = this;  
       if (file !== null)  
       {  
       window.setTimeout(BindFunctionToContextOnce(Application_Activate_FilePicker_DisplayFile, file), 1000);  
       }  
       else  
       {  
       window.setTimeout(Application_Activate_FilePicker_DisplayAbsence, 1000);  
       }  
       }  
         
       function Application_Activate_FilePicker_DisplayFile()  
       {  
       var file = this;  
       new Windows.UI.Popups.MessageDialog("A file was selected:  " + file.name, "File Selected").showAsync();  
       }  
       function Application_Activate_FilePicker_DisplayAbsence()  
       {  
       new Windows.UI.Popups.MessageDialog("No file was selected.", "No File Selected").showAsync();  
       }  
         
       function Application_Activate_FilePicker_FilePickerFailed(problem)  
       {  
       var user = this;  
       if (problem.number === -2147023496 /* ~~0x80070578 */)  
       {  
       if (user !== null)  
       {  
       var downloadsFolderClass = Windows.Storage.DownloadsFolder;  
       if (downloadsFolderClass.createFolderForUserAsync !== void(0))  
       {  
       downloadsFolderClass.createFolderForUserAsync(user, "TemporaryFolder", Windows.Storage.CreationCollisionOption.failIfExists).then(BindFunctionToContextOnce(Application_Activate_FilePicker_TemporaryFolderCreated, user), BindFunctionToContextOnce(Application_Activate_FilePicker_TemporaryFolderFailed, user));  
       }  
       }  
       }  
       }  
         
       function Application_Activate_FilePicker_TemporaryFolderCreated(storageFolder)  
       {  
       var user = this;  
       storageFolder.deleteAsync(Windows.Storage.StorageDeleteOption.permanentDelete).then(BindFunctionToContextOnce(Application_Activate_FilePicker_TemporaryFolderDeleted, user), BindFunctionToContextOnce(Application_Activate_FilePicker_TemporaryFolderFailed, user));  
       }  
         
       function Application_Activate_FilePicker_TemporaryFolderDeleted()  
       {  
       var user = this;  
       Application_Activate_FilePicker_TemporaryFolderFailed.call(user, null);  
       }  
         
       function Application_Activate_FilePicker_TemporaryFolderFailed(problem)  
       {  
       var user = this;  
       var openPicker = BuildFileOpenPickerForUser(user);  
       openPicker.pickSingleFileAsync().then(BindFunctionToContextOnce(Application_Activate_FilePicker_FilePicked, user), BindFunctionToContextOnce(Application_Activate_FilePicker_FilePickerFailed, user));  
       }  
         
       function BindFunctionToContextOnce(targetFunction, targetObject)  
       {  
       return function BindFunctionToContextOnce_Callback()  
       {  
       var localFunction = targetFunction;  
       var localTarget = targetObject;  
       targetFunction = null;  
       targetObject = null;  
       return localFunction.apply(localTarget, arguments);  
       };  
       }  
         
       function BuildFileOpenPickerForUser(user)  
       {  
       var fileOpenPickerClass = Windows.Storage.Pickers.FileOpenPicker;  
       var openPicker;  
       if ((user !== null) && (fileOpenPickerClass.createForUser !== void(0)))  
       {  
       openPicker = fileOpenPickerClass.createForUser(user);  
       }  
       else  
       {  
       openPicker = new fileOpenPickerClass();  
       }  
       openPicker.settingsIdentifier = "Specimen";  
       openPicker.fileTypeFilter.replaceAll(["*"]);  
       openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.downloads;  
       return openPicker;  
       }  
    

    Update (9 July 2022): Based on additional research from @Clément Micard (C#, minimum build 19041 and target build 19041), we now recommend calling Windows.Storage.StorageFolder.GetFolderFromPathForUserAsync with any path, but we suggest acting in good faith and specifying a valid path (like your application's local temporary folder Windows.Storage.ApplicationData.Current.TemporaryFolder.Path). Ignore the result and then try your file picker operation. I can confirm this strategy is also functional for UWP JavaScript, and has the nice benefit of no disk writes and leftover folders. For UWP sandboxed applications, you do not need the broadFileSystemAccess capability to make use of this strategy; just be sure to catch the access denied exception (error code 0x80070005).