简体   繁体   中英

Windows 8 Metro App File Share Access

I am developing a Windows 8 Metro app, and we intend to deploy it to only a few tablets within our company. It's not meant for the Windows Store.

We need the app to access some directories on the company's network share, but forcing the user to use a FilePicker isn't what we want.

Our first attempt was to use await StorageFolder.GetFolderFromPathAsync("J:\\\\"); . This didn't work, and produced the following exception:

An unhandled exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll

WinRT information: Cannot access the specified file or folder (J:\\). The item is not in a location that the application has access to (including application data folders, folders that are accessible via capabilities, and persisted items in the StorageApplicationPermissions lists). Verify that the file is not marked with system or hidden file attributes.

Additional information: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

So we tried replacing "J:\\" with the network path the drive was mapped to. This also didn't work, and we got this exception:

An unhandled exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll

WinRT information: Cannot access the specified file (\\\\domain\\path\\JDrive). Verify that there is a file type association declared in the manifest for this type of file and that the file is not marked with the system or hidden file attributes.

Additional information: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

Our app has the following Capabilities:

  • Enterprise Authentication
  • Internet (Client)
  • Private Networks (Client & Server)

Our app has no Declarations

This is all very reasonable for a Windows Store app, but is there any workaround for a simple in-house app that isn't going to the Store?

Here is a quickstart on file access in JavaScript and VB/C#/C++ .

In addition, this article on file access and permissions in Windows Store apps might be useful. From this article, it looks like you are using the right capabilities, but there is a note:

Note: You must add File Type Associations to your app manifest that declare specific file types that your app can access in this location.

This makes sense with the error message that you're seeing. Can you try that? Here's an article on how to do it: http://msdn.microsoft.com/en-us/library/windows/apps/hh452684.aspx

I'm also assuming that you've already checked and ensured that the file that you want to access is not marked with the system or hidden file attributes (as per the error message).

We're currently working around this by accessing the file share through a WCF Web Service . It's far from ideal, but it gets us what we need.

Below is the code that manages to write a file to a network share from WinRT device (Microsoft Surface RT) running Windows 8.1 RT. The essential bits are that:

  • share is accessed using a UNC path
  • share is public
  • application manifest mentions the file type that is written
  • application has the proper capabilities

The basic mechanism is described here: http://msdn.microsoft.com/en-US/library/windows/apps/hh967755.aspx

As a bonus, this shows how to capture output to standard output in a WinRT application.

The code:

#include "App.xaml.h"
#include "MainPage.xaml.h"
#include <ppltasks.h>

using namespace TestApp;

using namespace Platform;
using namespace Windows::UI::Xaml::Navigation;
using namespace Concurrency;

// Anything that is written to standard output in this function will be saved to a file on a network share
int MAIN(int argc, char** argv)
{
    printf("This is log output that is saved to a file on a network share!\n");
    return 0;
}

static char buffer[1024*1024];

Windows::Foundation::IAsyncOperation<int>^ MainPage::RunAsync()
{
    return create_async([this]()->int {
        return MAIN(1, NULL);
    });
}

using namespace concurrency;
using namespace Platform;
using namespace Windows::Storage;
using namespace Windows::System;

void MainPage::Run()
{
    //capture stdout in buffer
    setvbuf(stdout, buffer, _IOFBF, sizeof(buffer));

    task<int> testTask(RunAsync());

    testTask.then([this](int test_result)
    {
        size_t origsize = strlen(buffer) + 1;
        wchar_t* wcstring = new wchar_t[sizeof(buffer)* sizeof(wchar_t)];

        size_t  converted_chars = 0;
        mbstowcs_s(&converted_chars, wcstring, origsize, buffer, _TRUNCATE);
        String^ contents = ref new Platform::String(wcstring);
        delete [] wcstring;

        Platform::String^ Filename = "log_file.txt";
        Platform::String^ FolderName = "\\\\MY-SHARE\\shared-folder";

        create_task(Windows::Storage::StorageFolder::GetFolderFromPathAsync(FolderName)).then([this, Filename, contents](StorageFolder^ folder)
        {
            create_task(folder->CreateFileAsync(Filename, CreationCollisionOption::ReplaceExisting)).then([this, contents](StorageFile^ file)
            {
                create_task(FileIO::WriteTextAsync(file, contents)).then([this, file, contents](task<void> task)
                {
                    try
                    {
                        task.get();
                        OutputBox->Text = ref new Platform::String(L"File written successfully!");
                    }
                    catch (COMException^ ex)
                    {
                        OutputBox->Text = ref new Platform::String(L"Error writing file!");
                    }
                });
            });
        });
    });
}

MainPage::MainPage()
{
    InitializeComponent();
    Run();
}

The manifest:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
  <Identity Name="6f9dc943-75a5-4195-8a7f-9268fda4e548" Publisher="CN=Someone" Version="1.1.0.1" />
  <Properties>
    <DisplayName>TestApp</DisplayName>
    <PublisherDisplayName>Someone</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
    <Description>TestApp</Description>
  </Properties>
  <Prerequisites>
    <OSMinVersion>6.3</OSMinVersion>
    <OSMaxVersionTested>6.3</OSMaxVersionTested>
  </Prerequisites>
  <Resources>
    <Resource Language="x-generate" />
  </Resources>
  <Applications>
    <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="TestApp.App">
      <m2:VisualElements DisplayName="TestApp" Description="TestApp" BackgroundColor="#222222" ForegroundText="light" Square150x150Logo="Assets\Logo.png" Square30x30Logo="Assets\SmallLogo.png">
        <m2:DefaultTile>
          <m2:ShowNameOnTiles>
            <m2:ShowOn Tile="square150x150Logo" />
          </m2:ShowNameOnTiles>
        </m2:DefaultTile>
        <m2:SplashScreen Image="Assets\SplashScreen.png" />
      </m2:VisualElements>
      <Extensions>
        <Extension Category="windows.fileTypeAssociation">
          <FileTypeAssociation Name="text">
            <DisplayName>Text file</DisplayName>
            <SupportedFileTypes>
              <FileType ContentType="text/plain">.txt</FileType>
            </SupportedFileTypes>
          </FileTypeAssociation>
        </Extension>
      </Extensions>
    </Application>
  </Applications>
  <Capabilities>
    <Capability Name="musicLibrary" />
    <Capability Name="picturesLibrary" />
    <Capability Name="videosLibrary" />
    <Capability Name="internetClient" />
    <Capability Name="internetClientServer" />
    <Capability Name="enterpriseAuthentication" />
    <Capability Name="privateNetworkClientServer" />
  </Capabilities>
</Package>

Have a look at this question: Accessing Network shared paths in WinRT

There is no way to access the shared location in Win8 App.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM