locked
StorageDataSource: any known issues while using it to access an external drive? RRS feed

  • Question

  • Hello guys.

    I've built a simple demo project which uses autoplay to show the pictures found in an external camara volume. Everything was working fine until I've decided to let the StorageDataSource do the heavy work of getting me the files. The problem is that my app crashes with an unspecified error when the app is activated in response to autoplay run. Is this a known issue?

    btw, here's the code of my HTML page:

         

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>autoplay</title>


        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.0.6/css/ui-light.css" rel="stylesheet">
        <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
        <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>


        <!-- autoplay references -->
        <link href="/css/default.css" rel="stylesheet">
        <script src="/js/default.js"></script>
    </head>
    <body>
        <h1>Galeria de imagens</h1>

        <div id="galeria"
            data-win-control="WinJS.UI.ListView"
            data-win-options="{
                layout: { type: WinJS.UI.GridLayout }}">
        </div>
        <div id="appBar" data-win-control="WinJS.UI.AppBar" 
            class="appBar"
            data-win-options="{placement:'bottom'}">                           
            <button data-win-control="WinJS.UI.AppBarCommand" 
                data-win-options="{
                    id:'abrir',
                    label:'Abrir',
                    icon:'openfile',
                    tooltip:'Mostrar imagens em pasta' }">
            </button>   
        </div>
    </body>
    </html>

    And here's the JS code I'm using:

        

    // For an introduction to the Blank template, see the following documentation:
    // http://go.microsoft.com/fwlink/?LinkId=232509
    (function () {
        "use strict";


        var app = WinJS.Application;
        var lista = null;
        var folder = null;
        app.onactivated = function (eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.file) {
                folder = eventObject.detail.files[0];
            }
            WinJS.UI.processAll()
                .done(function () {
                    document.getElementById("abrir").addEventListener("click", abreGaleria);
                    lista = document.getElementById("galeria").winControl;
                    inicializaLista();
                });
        };


        function inicializaLista() {        
            if (!folder) return;
            var queryOptions = new Windows.Storage.Search.QueryOptions(
            Windows.Storage.Search.CommonFileQuery.orderByName, [".jpg"]);
            var query = folder.createFileQueryWithOptions(queryOptions);
            var options = {
                mode: Windows.Storage.FileProperties.ThumbnailMode.picturesView,
                requestedTumbnailSize: 190,
                tumbnailOptions: Windows.Storage.FileProperties.ThumbnailOptions.useCurrentScale
            };
            var storage = new WinJS.UI.StorageDataSource(query, options);
            lista.itemTemplate = gerarItem;
            lista.itemDataSource = storage;
        }
        function gerarItem(item) {
            return item.then(function(aux){
                var div = document.createElement("div");
                div. className = "imageGallery";
                var img = document.createElement("img");
                img.src = URL.createObjectURL(aux.data.thumbnail);;
                div.appendChild(img);
                return div;
            });
        }

        function abreGaleria() {
            var folderPicker = new Windows.Storage.Pickers.FolderPicker();
            folderPicker.fileTypeFilter.replaceAll([".jpg"]);
            folderPicker.pickSingleFolderAsync()
                .done(function (item) {
                    if (!item) return;
                    folder = item;
                    inicializaLista();
                });
        }


        app.oncheckpoint = function (eventObject) {
            // TODO: This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the 
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // eventObject.setPromise(). 
        };


        app.start();
    })();

    And finally, here's my manifest:

    <?xml version="1.0" encoding="utf-8"?>
    <Package xmlns="http://schemas.microsoft.com/appx/2010/manifest">
      <Identity Name="90181ce0-c78c-4ea1-8ed3-34aa4539107a" Version="1.0.0.0" Publisher="CN=labreu" />
      <Properties>
        <DisplayName>autoplay</DisplayName>
        <Description>autoplay</Description>
        <PublisherDisplayName>labreu</PublisherDisplayName>
        <Logo>images\storelogo.png</Logo>
      </Properties>
      <Prerequisites>
        <OSMinVersion>6.2</OSMinVersion>
        <OSMaxVersionTested>6.2</OSMaxVersionTested>
      </Prerequisites>
      <Resources>
        <Resource Language="x-generate" />
      </Resources>
      <Applications>
        <Application Id="App" StartPage="default.html">
          <VisualElements DisplayName="autoplay" Logo="images\logo.png" SmallLogo="images\smalllogo.png" Description="autoplay" ForegroundText="light" BackgroundColor="#000000">
            <DefaultTile ShowName="allLogos" />
            <SplashScreen Image="images\splashscreen.png" />
          </VisualElements>
          <Extensions>
            <Extension Category="windows.fileTypeAssociation" StartPage="default.html">
              <FileTypeAssociation Name="fotos">
                <DisplayName>Fotos</DisplayName>
                <SupportedFileTypes>
                  <FileType ContentType="img/jpeg">.jpg</FileType>
                  <FileType ContentType="img/x-png">.png</FileType>
                  <FileType>.gif</FileType>
                </SupportedFileTypes>
              </FileTypeAssociation>
            </Extension>
            <Extension Category="windows.autoPlayContent">
              <AutoPlayContent>
                <LaunchAction Verb="show" ActionDisplayName="Mostra fotos" ContentEvent="ShowPicturesOnArrival" />
              </AutoPlayContent>
            </Extension>
          </Extensions>
        </Application>
      </Applications>
      <Capabilities>
        <Capability Name="removableStorage" />
        <Capability Name="internetClient" />
      </Capabilities>
    </Package>

    Any ideas? thanks.


    Luis Abreu

    Saturday, March 31, 2012 2:54 PM

Answers

  • Luis,

    Since the error involves Windows.Storage.BulkAccess.FileInformationFactory and the StorageFolder retrieved from Content Autoplay, a workaround would be setup the query as you're doing, and do a query.getFilesAsync() to get the list of files, instead of passing the query and options to WinJS.UI.StorageDataSource. You would then loop through the files to get the thumbnails.  Admittedly, this is more complex and slower than using  bulk access.

    Another option is to try to re-acquire the StorageFolder using enumeration.  Basically, when you get the storage from Autoplay, call Windows.Storage.KnownFolders.getRemovableDevices to get a list of existing storages.  You can then loop through the list of existing storages  (acquired outside of Autoplay) and find the one that matches the storage.name property for the Autoplay storage.  Once you found the alternate storage, you can proceed to use that in your StorageDataSource query.  This isn't foolproof because storages can have the same name, but at least you can keep the existing code.

    HTH,

    Lisa



    Thursday, April 5, 2012 12:23 AM

All replies

  • Luis,

    If you debug the app by launching it in the debugger, switching away, and then triggering Autoplay, you should see additional information about what is triggering the unspecified error.  You should also be able to step to the line of code that returns the error.

    Also, I assume the typos you had pasted above not-present in the actual code (e.g. requestedThumbnailSize, thumbnailOptions) as these would also trigger errors.

    Hope this helps,

    Lisa Ong [MSFT]




    Monday, April 2, 2012 6:12 PM
  • Hi Luis,

    This may be because you are not null-checking the thumbnail property before calling "createObjectURL". Thumbnails on a removable drive will often not be pre-cached, so the initial thumbnail value will be null. Calling createObjectURL with null would result in an app crash.

    If you look at the storage datasource sample, here is the recommended renderer:

        function storageRenderer(itemPromise) { 
            return itemPromise.then(function (listviewItem) { 
                var result = document.createElement("div"); 
                result.className = "win-listview-mediumImageTemplate"; 
     
                if (listviewItem.data.thumbnail) { 
                    var url = URL.createObjectURL(listviewItem.data.thumbnail, false); 
                    result.innerHTML = "<img src='" + url + "'/>"; 
                } 
                else { 
                    result.innerHTML = "<div></div>"; 
                } 
     
                return result; 
            }); 
        }; 

    Don't forget to specify "false" when creating the object URL, otherwise your application may be leaking objects! If the initial thumbnail is null, the datasource will ensure that your renderer function is called again when the thumbnail becomes available, so there's no need to have a fallback.

    Marc

    Monday, April 2, 2012 6:13 PM
  • Hello guys.

    I'm getting the error when I call the StorageDataSource constructor. More precisely, on this line:

     this._loader = new Windows.Storage.BulkAccess.FileInformationFactory(this._query, mode, size, flags, delayLoad);

    Regarding  the error message, here's the stack I'm getting:

    WinRTError: Unspecified error


       at Anonymous function (ms-appx://microsoft.winjs.0.6/js/ui.js:8957:9)
       at Anonymous function (ms-appx://microsoft.winjs.0.6/js/ui.js:9085:13)
       at inicializaLista (ms-appx://ddb40024-214d-478b-9cd4-134f50821232-j5smj7mk4vxrp/js/default.js:33:9)
       at Anonymous function (ms-appx://ddb40024-214d-478b-9cd4-134f50821232-j5smj7mk4vxrp/js/default.js:18:17)
       at doneSuccess (ms-appx://microsoft.winjs.0.6/js/base.js:1220:9)
       at done (ms-appx://microsoft.winjs.0.6/js/base.js:1048:13)
       at onactivated (ms-appx://ddb40024-214d-478b-9cd4-134f50821232-j5smj7mk4vxrp/js/default.js:14:9)
       at wrapperFunction (ms-appx://microsoft.winjs.0.6/js/base.js:403:29)
       at dispatchOne (ms-appx://microsoft.winjs.0.6/js/base.js:5408:57)
       at dispatchEvent (ms-appx://microsoft.winjs.0.6/js/base.js:5408:21)

    Unfortunately, I can't debug into the FileInformationFactory method adn I think there's not much in the error message. Btw, the code that I've written before is more than enough for reproducing the project (that is, if anyone is interested and has the required time).

    Thanks.


    Luis Abreu

    Monday, April 2, 2012 8:55 PM
  • Thanks - can you confirm that the typos that Lisa pointed out above do not exist in your code? These could definitely trigger a crash when constructing the datasource.

    <quote>

    Also, I assume the typos you had pasted above not-present in the actual code (e.g. requestedThumbnailSize, thumbnailOptions) as these would also trigger errors.

    </quote>

    Monday, April 2, 2012 11:22 PM
  • Hello Marc.

    Yes, I've fixed those and I can confirm that they weren't causing the error (though they weren't also doing anything ). Notice that I also have an appbar which allows me to open a folder that has the pictures I want to show.  When the user chooses that option, that same code is reused and it works without any problems...

    any more ideas?

    thanks.


    Luis Abreu

    Tuesday, April 3, 2012 7:45 AM
  • Luis,

    Just a clarification to help us isolate the issue: for the working scenario where the user selects a folder from the appbar, did you try this with folders selected on the external USB drive? 

    Thanks,

    Lisa

    Tuesday, April 3, 2012 6:17 PM
  • Hello Lisa.

    Yes, I've just tested it now with my phone: picking the external drive from the appbar works as expected.


    Luis Abreu

    Tuesday, April 3, 2012 7:17 PM
  • Luis,

    Thanks for the confirmation. I assume you're using the Consumer Preview build.  I'll investigate and get back to you soon.  

    Lisa

    Tuesday, April 3, 2012 7:44 PM
  • Yes, that's the version I'm using.

    thanks again.


    Luis Abreu

    Tuesday, April 3, 2012 9:14 PM
  • Luis,

    Thanks for reporting this.  I'm able to reproduce the same error and I've forwarded this issue to the team to investigate. 

    Lisa

    Wednesday, April 4, 2012 8:00 PM
  • Thank you Lisa.

    Please let me know if there's a workaround for this problem.

    thanks again.


    Luis Abreu

    Thursday, April 5, 2012 12:04 AM
  • Luis,

    Since the error involves Windows.Storage.BulkAccess.FileInformationFactory and the StorageFolder retrieved from Content Autoplay, a workaround would be setup the query as you're doing, and do a query.getFilesAsync() to get the list of files, instead of passing the query and options to WinJS.UI.StorageDataSource. You would then loop through the files to get the thumbnails.  Admittedly, this is more complex and slower than using  bulk access.

    Another option is to try to re-acquire the StorageFolder using enumeration.  Basically, when you get the storage from Autoplay, call Windows.Storage.KnownFolders.getRemovableDevices to get a list of existing storages.  You can then loop through the list of existing storages  (acquired outside of Autoplay) and find the one that matches the storage.name property for the Autoplay storage.  Once you found the alternate storage, you can proceed to use that in your StorageDataSource query.  This isn't foolproof because storages can have the same name, but at least you can keep the existing code.

    HTH,

    Lisa



    Thursday, April 5, 2012 12:23 AM
  • Hello Lisa.

    I'm already using option 1. Haven't tested 2, so I'll probably give it a go when I have some free time.

    I'm hoping to see this fixed in the next release. Am I expecting too much? :)

    thanks.


    Luis Abreu

    Thursday, April 5, 2012 2:49 PM
  • Hi Luis,

    This issue is being investigated by the dev team so I don't have an ETA at the moment.  I'll update this as soon as I have more details.

    Thanks,

    Lisa

    Thursday, April 5, 2012 6:31 PM
  • Hello again.

    any more info on this? thanks.


    Luis Abreu

    Sunday, June 10, 2012 8:47 PM
  • Hi Luis,

    This issue is fixed in Release Preview. Let me know if you see otherwise.

    Thanks,

    lisa

    Sunday, June 10, 2012 11:07 PM
  • Thanks!

    Luis Abreu

    Monday, June 11, 2012 9:11 AM