locked
How to share a file that has been created on the fly? RRS feed

  • Question

  • Somehow I am not able to share an image file that my program creates on the fly in the roaming folder using the DataTransferManager - all I am getting is a "There is a problem with the data..." message. When I share a Bitmap instead it works fine, the problem is that not all Share targets accept Bitmaps (actually I found not a single one so far, except for the Share Target example)

    The file is created in the DeferredRequestHandler inside the ApplicationData.Current.RoamingFolder - not sure if that might be the problem - all the examples I found use files that were picked by the user using the file picker.

      public void ShareSourceLoad()
            {
                DataTransferManager datatransferManager;
                datatransferManager = DataTransferManager.GetForCurrentView();
                datatransferManager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(this.DataRequested);
            }
    
            void DataRequested(DataTransferManager sender, DataRequestedEventArgs e)
            {
                e.Request.Data.Properties.Title = "Shared Image File";
                e.Request.Data.Properties.Description = "A Test";
        e.Request.Data.SetDataProvider(StandardDataFormats.StorageItems, OnDeferredFileRequestedHandler);
            }
    
          
            async void OnDeferredFileRequestedHandler(DataProviderRequest request)
            {
    
                DataProviderDeferral deferral = request.GetDeferral();
    
                StorageFile filetoShare = await roamingFolder.CreateFileAsync("shared_image.png", CreationCollisionOption.ReplaceExisting);
                if (filetoShare != null)
                {
                    ProcessBitmap saveMap = new ProcessBitmap(canvasInfo.Width, canvasInfo.Height, 0xffffffff);
    
                    saveMap.compositePixels(canvasInfo.drawingMap);
                    await BitmapUtils.saveToFile(saveMap, filetoShare);
                   
                    List<IStorageItem> shares = new List<IStorageItem>();
                    shares.Add(filetoShare);
                    request.SetData(shares);
                    
                }
                 deferral.Complete();
    
            }

    Monday, May 14, 2012 10:34 PM

Answers

  • Saving bitmap files to the roaming folder does work for me when I use it for app suspension, so I think it works. But I probably should make sure that the file really exists.
    Sunday, May 20, 2012 9:08 AM

All replies

  • If you dynamically create a bitmap and try to share it, does it work?

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    Tuesday, May 15, 2012 6:55 PM
    Moderator
  • Are you sure that bitmap actually getting saved? Files saved into roaming folder are subject to quota and that could be the problem.
    Tuesday, May 15, 2012 9:49 PM
  • Yes, that does work. But as I said - it looks like not many share targets accept plain Bitmaps yet, that's why I am looking for a way to share bitmap files.
    Sunday, May 20, 2012 9:06 AM
  • Saving bitmap files to the roaming folder does work for me when I use it for app suspension, so I think it works. But I probably should make sure that the file really exists.
    Sunday, May 20, 2012 9:08 AM
  • The file is definitely getting saved since I am using the same method for suspending/reactivation where it works fine.

    But I noticed one thing which might be related: when I am saving a generated png to the pictures library and open that folder in explorer whilst my app is still running, I cannot open the image since explorer tells me that the file is still in use. I do not see that I keep a reference to that file after saving and I was also looking for some way how to release a possible lock from within my app, but didn't find any command for that. So my question is - what can I do to release the file after I have saved it?

    Wednesday, May 23, 2012 8:41 PM
  • Have you tried disposing the StorageFile when you are done with it?

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    Thursday, May 24, 2012 1:13 PM
    Moderator
  • I was looking for some kind of Dispose() method in StorageFile, but didn't find any. Do you mean I should try myStorageFile = null? I was expecting that since myStorageFile  is a local object it would automatically get disposed when the method is done.
    • Edited by Quasimondo Friday, May 25, 2012 7:52 AM
    Friday, May 25, 2012 7:52 AM
  • I really thought that there would be a dispose method on StorageFile but it does appear that I am wrong.  Objects will get collected when they go out of scope but it's not instant.  I might as well ask if you actually tried null and if it worked?

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    Tuesday, May 29, 2012 3:26 PM
    Moderator
  • Setting the StorageFille to null does not make a difference. But what I noticed now is that the garbage collections seems to get triggered once I interact with the application again after the saving. The file becomes accessible then to other applications (but it does not work, if I just wait for a few seconds but do nothing). At least that's a start, but it does not solve my sharing problem yet, except if I figure out a way how to trigger garbage collection without user interaction.
    • Edited by Quasimondo Tuesday, May 29, 2012 4:26 PM
    Tuesday, May 29, 2012 4:26 PM
  • Try GC.Collect and see if that helps.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    Wednesday, May 30, 2012 1:06 PM
    Moderator
  • I have tried that already - no cigar.
    Wednesday, May 30, 2012 1:25 PM
  • Can you try running ProcMon and Process Explorer to see what applications are holding onto your file?


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    Monday, June 4, 2012 4:03 PM
    Moderator
  • In ProcMon I can see that the first process that accesses my image file is PickerHost.exe which does a CreateFile, CloseFile and 2 QueryDirectory ops.

    This is followed by several accesses through RuntimeBroker.exe, MsMpEng.exe and SearchProtocolHost.exe

    Then the file gets actually written by my app (several WriteFile operations, followed by a FlushBuffersFile, but no CloseFile operation), this is interleaved with and followed by operations from MsMpEng.exe and SearchProtocolHost.exe again.

    What I can see is that the moment I interact with the application again (the way I described previously) there is one "CloseFile" operation by RuntimeBroker.exe after which the image becomes unlocked and accessible by Explorer.EXE.

    Tuesday, June 5, 2012 12:14 PM
  • Good news. I finally managed to get the sharing of the file working. The first thing that was wrong (or at least unnecessary) was the way I had constructed the deferred file request handler. Turned out that I can render and send the image file directly inside the DataRequested handler. This already made the "There is a problem with the data..." message go away and listed the "Mail" share target.

    Still in the mail share target the image file was being marked as "locked". But this time setting the reference to the StorageFile to null inside my app and forcing a garbage collection releases it. Here's the code that works for me:

    public void ShareSourceLoad()
    {
                DataTransferManager datatransferManager;
                datatransferManager = DataTransferManager.GetForCurrentView();
                datatransferManager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(this.DataRequested);
     }
    
    async void DataRequested(DataTransferManager sender, DataRequestedEventArgs e)
    {
                e.Request.Data.Properties.Title = "Smart Title";
                e.Request.Data.Properties.Description = "Shared by Me";
    
                DataRequestDeferral deferral = e.Request.GetDeferral();
    
                StorageFile filetoShare = await roamingFolder.CreateFileAsync("SharedImage.png", CreationCollisionOption.ReplaceExisting);
                if (filetoShare != null)
                {
                 
                   await MyCustomHelperClass.RenderMyBitmap(filetoShare ) 
    
                    List<IStorageItem> shares = new List<IStorageItem>();
                    shares.Add(filetoShare);
                    e.Request.Data.SetStorageItems(shares);
                    filetoShare = null;
                    shares = null;
                    GC.Collect();
                   
    
                }
                deferral.Complete();
             }

    Friday, June 8, 2012 5:37 PM
  • I'm really glad you got it.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    Friday, June 8, 2012 7:05 PM
    Moderator