Drake
Drake

Reputation: 73

Unable to open files in c++ (directx app) access denied

I'm trying to open a DDS file with my DirectX 11 project, however, most of the cases, it refuses to open it. Everytimes it fails, I get E_ACCESSDENIED error. The only way to make it working is to put the relative path to the current directory or subdirectory. If it's a relative path to a parent directory, or if it's a absolute path, the function will fail.

The problem is that I wish to open the image using FileOpenPicker, so in every cases, I get an absolute path...

I will share my functions:

void Element::FileOpenDialog()
{
    FileOpenPicker^ fileOpenPicker = ref new FileOpenPicker();
    fileOpenPicker->ViewMode = PickerViewMode::Thumbnail;
    fileOpenPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    fileOpenPicker->CommitButtonText = "Load";
    fileOpenPicker->FileTypeFilter->Append(".dds");
    create_task(fileOpenPicker->PickSingleFileAsync()).then([this](StorageFile^ file)
    {
        if (file)
        {
            m_fullPath = const_cast<wchar_t*>(file->Path->Data());
            wcout << m_fullPath  << endl; // prints the correct path of the selected file

            m_loadedImage = false;
        }
        m_choseImage = true; // Checking in another code if the user chose an image to load.
    });
}

And then, I call the function to load the texture...

bool Texture::LoadFile(wchar_t* path, GameWindow^ gameWindow)
{
    m_gameWindow = gameWindow;
    ComPtr<ID3D11Resource> resource = nullptr;
    if (!FH::ThrowIfFailed(CreateDDSTextureFromFile(m_gameWindow->dev.Get(), L"texture.dds", resource.GetAddressOf(), m_texture.ReleaseAndGetAddressOf()))) return false; // Works
    if (!FH::ThrowIfFailed(CreateDDSTextureFromFile(m_gameWindow->dev.Get(), L"texture\\texture.dds", resource.GetAddressOf(), m_texture.ReleaseAndGetAddressOf()))) return false; // Works
    if (!FH::ThrowIfFailed(CreateDDSTextureFromFile(m_gameWindow->dev.Get(), L"..\\texture.dds", resource.GetAddressOf(), m_texture.ReleaseAndGetAddressOf()))) return false; // E_ACCESSDENIED
    if (!FH::ThrowIfFailed(CreateDDSTextureFromFile(m_gameWindow->dev.Get(), path, resource.GetAddressOf(), m_texture.ReleaseAndGetAddressOf()))) return false; // E_ACCESSDENIED
    return true;
}

Well, since I have no idea why, that's why I come here to request your help.

Thank you very much!

Upvotes: 0

Views: 348

Answers (1)

Chuck Walbourn
Chuck Walbourn

Reputation: 41127

A UWP application does not have direct file access to the location the file picker is selecting. The FileOpenPicker is a broker which does it on your behalf, but you can't use standard file I/O, only WinRT APIs on it. Keep in mind that the file picked may also not even be on the local file system. The only file locations you have direct I/O access to is your installed folder (read-only), a temporary folder (read-write), and a application data folder (read-write).

See File access and permissions (Windows Runtime apps) on MSDN for more information.

A solution is to copy the selected brokered file to a temporary file location that you do have access to, and then use CreateDDSTextureFromFile on the temporary copy.

#include <ppltasks.h>
using namespace concurrency;

using Windows::Storage;
using Windows::Storage::Pickers;

create_task(openPicker->PickSingleFileAsync()).then([](StorageFile^ file)
{
    if (file)
    {
        auto tempFolder = Windows::Storage::ApplicationData::Current->TemporaryFolder;
        create_task(file->CopyAsync(tempFolder, file->Name, NameCollisionOption::GenerateUniqueName)).then([](StorageFile^ tempFile)
        {
            if (tempFile)
            {
                HRESULT hr = CreateDDSTextureFromFile(..., tempFile->Path->Data(), ...);
                DeleteFile(tempFile->Path->Data());
                DX::ThrowIfFailed(hr);
            }
        });
    });

This is covered in detail on the DirectX Tool Kit wiki, with the write case covered there as well.

Upvotes: 1

Related Questions