none
LaunchFileAsync 失败可能是什么原因? RRS feed

  • 问题

  • 最近出现了与 LaunchFileAsync 有关的问题,而且出现了电脑和手机表现不一致的情况。(这真是令人尴尬)(说好的大统一呢)

    异常表现:

    首先,这是我的 APP 的某一页的内容

    (由于大小限制,图片显示不全,在 http://bbs.wfun.com/forum.php?mod=viewthread&tid=910240&page=1&extra=#post_14396209 发表了同样的帖子)

    在导航到这一页时,OnNavigatedTo 会执行读取文件操作:

    //StorageFolder filesFolder, filesCacheFolder; 和 object apm; 定义在全局变量中
    //filesFolder 存储高清原图,filesCacheFolder 存储略缩图,横向200px,纵向由原图纵横比决定,每张约107KB
    //AddedPhotosManager 是我自己写的一个类
    
    apm = e.Parameter;
    
    filesFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("photos", CreationCollisionOption.OpenIfExists);
    filesCacheFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("photosCache", CreationCollisionOption.OpenIfExists);
    
    //传递参数是空的代表未加载过
    if (apm == null)
    {
        apm = new AddedPhotosManager();
        IReadOnlyList<StorageFile> fileOL = await filesFolder.GetFilesAsync();
        IReadOnlyList<StorageFile> fileCacheOL = await filesCacheFolder.GetFilesAsync();
        string sum = fileOL.Count.ToString();
        Image im, im2;
        for (int i = 0; i < fileOL.Count; i++)
        {
            //粗暴的文字提示
            progressText.Text = "即将完成(" + (i + 1).ToString() + "/" + sum + ")\n在此应用关闭前仅加载一次,除非你在此期间使用共享或文件关联的方式添加了新的图片。";
    
            //在全局变量的 Lis t中添加文件以便接下来的管理(主要是“删除”)
            ((AddedPhotosManager)apm).filesList.Add(fileOL[i]);
            ((AddedPhotosManager)apm).filesCacheList.Add(fileCacheOL[i]);
    
            //根据 107 KB 的缩略图从 StorageFile 生成 Image
            im = await AddedPhotosManager.getImage(fileCacheOL[i]);
    
            //也添加到全局变量中以便在页面导航时传递该变量,实现“在此应用关闭前仅加载一次”
            ((AddedPhotosManager)apm).imagesList.Add(im);
    
            //另生成一个新的 Image 以便重复添加到 GridView 中
            im2 = new Image();
            im2.Height = im.Height;
            im2.Width = im.Width;
            im2.Source = im.Source;
            im2.Stretch = Stretch.UniformToFill;
            photosGridView.Items.Add(im2);
    
            selectAllAppBarButton.Visibility = Visibility.Visible;
        }
    }
    
    //已加载过图片
    else
    {
        Image i2;
        foreach (Image i in ((AddedPhotosManager)apm).imagesList)
        {
            i2 = new Image();
            i2.Height = i.Height;
            i2.Width = i.Width;
            i2.Source = i.Source;
            i2.Stretch = Stretch.UniformToFill;
            photosGridView.Items.Add(i2);
            selectAllAppBarButton.Visibility = Visibility.Visible;
        }
    }

    这些文件点击“打开”的时候都是正常的。文件信息里显示的文件夹也正常,是此应用的本地文件夹。

    bool x = await Launcher.LaunchFileAsync(((AddedPhotosManager)apm).filesList[photosGridView.SelectedIndex]);
    
    //如果打开失败
    if (!x)
    {
        //launchFailed是一个做得很像 MessageDialogue 的 Flyout
        launchFailedStackPanel.Width = mainGrid.ActualWidth - 44; //将其拉伸到与应用窗口一样宽
        launchFailed.ShowAt(Frame);
    }

    点击右下角的“+”,添加图片:

    FileOpenPicker picker = new FileOpenPicker();
    picker.CommitButtonText = "添加";
    picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    picker.ViewMode = PickerViewMode.Thumbnail;
    picker.FileTypeFilter.Add(".jpg");
    picker.FileTypeFilter.Add(".jpeg");
    picker.FileTypeFilter.Add(".png");
    StorageFile file2, file3;
    Image i, i2;
    
    IReadOnlyList<StorageFile> flist = await picker.PickMultipleFilesAsync();
    
    int x = 0;
    string sum = flist.Count.ToString();
    foreach (StorageFile file in flist)
    {
        //粗暴的文字提示
        x++;
        progressText.Text = "正在复制并缓存第" + x.ToString() + "张图片(共"+ sum +")…\n这可能需要较长时间。";
    
        //复制此文件到应用本地文件夹
        //fileDisplayName是int变量,其作用是当用户保存第一张图片时命名为0.jpg/.jpeg/.png,第二张图片时命名为1.jpg/.jpeg/.png,以此类推。我省略了与其有关的保存/读取代码。
        file2 = await file.CopyAsync(filesFolder, fileDisplayName.ToString() + file.FileType);
    
        //添加到全局变量的 List 里面
        ((AddedPhotosManager)apm).filesList.Add(file2);
    
        //获取缩略图并同时保存,详细代码在下一个框内
        file3 = await AddedPhotosManager.getThumbNail(file2);
    
        ((AddedPhotosManager)apm).filesCacheList.Add(file3);
        i = await AddedPhotosManager.getImage(file3);
        ((AddedPhotosManager)apm).imagesList.Add(i);
        i2 = new Image();
        i2.Height = i.Height;
        i2.Width = i.Width;
        i2.Source = i.Source;
        i2.Stretch = Stretch.UniformToFill;
        photosGridView.Items.Add(i2);
        selectAllAppBarButton.Visibility = Visibility.Visible;
        selectAllAppBarButton.IsChecked = false;
        fileDisplayName++;
    }

    internal static async Task<StorageFile> getThumbNail(StorageFile file)
    {
        StorageFolder cacheFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("photosCache", CreationCollisionOption.OpenIfExists);
        ImageProperties x = await file.Properties.GetImagePropertiesAsync();
        uint lim = 0;
    
        //将其横向像素设置为 200
        if (x.Height < x.Width)
        {
                lim = 200;
        }
        else
        {
                lim = 200 * x.Height / x.Width;
        }
    
        StorageItemThumbnail c = await file.GetThumbnailAsync(ThumbnailMode.PicturesView, lim, ThumbnailOptions.ResizeThumbnail);
        Windows.Storage.Streams.Buffer buf = new Windows.Storage.Streams.Buffer(Convert.ToUInt32(c.Size));
        IBuffer ibu = await c.ReadAsync(buf, buf.Capacity, InputStreamOptions.None);
    
        //保存到 filesCacheFolder 并返回该文件
        StorageFile f = await cacheFolder.CreateFileAsync(file.Name, CreationCollisionOption.ReplaceExisting);
        using (IRandomAccessStream strm = await f.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
        {
            await strm.WriteAsync(ibu);
        }
        return f;
    }

    此文件在电脑上正常打开,并且左侧显示的文件夹路径也正常,说明 StorageFile 应该没搞错,没把用户本来的文件错误地当成应用本地的文件。(我曾经怀疑是不是把 file 而不是 file2 添加到 List 里了。)但是在手机上不能打开。

    MSDN 官方解释:
    此 API 也对它可生成的文件类型有若干限制。很多包含可执行代码的文件类型,例如 .exe、.msi 和 .js 文件,在启动时都被阻止。恶意文件会修改系统,此限制可保护用户免受可能存在的恶意文件的危害。

    可是我 Launch 的都是一些 png,jpg,jpeg 这些人畜无害的文件啊,这是什么原因?


    • 已编辑 MIC 2014 2016年4月2日 14:54
    2016年4月2日 14:47