Starting with the "Anniversary Update" ("RS1" or build 10.0.14393) you can get the Win32 HANDLE from the StorageItem (file or folder) and create new named files (returning the HANDLE ) from within the StorageFolder . You do this using the new IStorageFolderHandleAccess and IStorageItemHandleAccess APIs.
Note These APIs accidentally fell into the WINAPI_PARTITION_DESKTOP section (they are not designed for the desktop, they are available for UWP). This will be discussed in future SDK updates.
To use one of these new COM interfaces, you simply have a QI StorageFile or StorageFolder for the interface. If the interface is not supported, this means that your application is running on a lower level OS (or perhaps the storage item is actually not supported by the real file, but rather a pseudo file). You can use these interfaces from C ++ (C ++ / CX or WRL) or from C #.
Here is a simple example of using FolderPicker so that the user FolderPicker location on his disk (which returns the brokerage object StorageFolder ), and then using the Win32 ReadFile and WriteFile APIs to read and write the file from this place.
As noted above, we must copy the declarations for the interface into our own code, because the real versions of the SDK are in the wrong API section. (I would advise against changing the SDK files to solve the problem). So first, our own header file, for example StorageHandleAccess.h , which copies the ads from the WindowsStorageCOM.h SDK file:
#pragma once
The following is a simple use of the API. This example uses a StorageFolder , the file name and the create flag (open or create) and tries to open (or create) a named file, read (or write) some text from (to) the file and write some output to the debug console.
The code is not particularly useful in the real world, but illustrates how to use the API. This can be used in an empty C ++ XAML project to replace the MainPage.xaml.cpp file (you only need to update the namespace):
#include "pch.h" #include "MainPage.xaml.h" #include <ppltasks.h> // TODO: Replace with your namespace #error Replace this with your real namespace using namespace FileHandleFromStorageFolder; // Uncomment out this line and delete the next line once the SDK is fixed //#include <WindowsStorageCOM.h> #include "StorageHandleAccess.h" // For ComPtr<> #include <wrl\client.h> // For HandleT<> #include <wrl\wrappers\corewrappers.h> __declspec(noreturn) inline void ThrowWithHRESULT(HRESULT hr, const wchar_t* message) { using namespace Platform; throw ref new Exception(hr, ref new String(message)); } __declspec(noreturn) inline void ThrowWithGetLastError(const wchar_t* message) { using namespace Platform; throw ref new Exception(HRESULT_FROM_WIN32(GetLastError()), ref new String(message)); } // Test is a simple test function. Pass in one of the HANDLE_CREATION_OPTIONS values // (eg, HCO_CREATE_ALWAYS or HCO_OPEN_ALWAYS) and the function will try and either // write to the file (if it empty) or read from it (if it not). void Test(Windows::Storage::StorageFolder^ folder, const wchar_t* filename, HANDLE_CREATION_OPTIONS options) { using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; // Get an IUnknown from the ref class, and then QI for IStorageFolderHandleAccess ComPtr<IUnknown> abiPointer(reinterpret_cast<IUnknown*>(folder)); ComPtr<IStorageFolderHandleAccess> handleAccess; HRESULT hr = abiPointer.As(&handleAccess); if (FAILED(hr)) ThrowWithHRESULT(hr, L"Can't QI"); // Standard RAII wrapper for HANDLEs that represent files HandleT<HandleTraits::FileHandleTraits>win32fileHandle; // This is roughly equivalent of calling CreateFile2 hr = handleAccess->Create(filename, options, HANDLE_ACCESS_OPTIONS::HAO_WRITE | HANDLE_ACCESS_OPTIONS::HAO_READ, HANDLE_SHARING_OPTIONS::HSO_SHARE_NONE, HANDLE_OPTIONS::HO_NONE, nullptr, win32fileHandle.GetAddressOf()); if (FAILED(hr)) ThrowWithHRESULT(hr, L"Can't access file"); // From here, it standard Win32 code - nothing WinRT specific at all LARGE_INTEGER size{ 0 }; if (FALSE == GetFileSizeEx(win32fileHandle.Get(), &size)) ThrowWithGetLastError(L"Can't get file size"); static const DWORD BUFFER_SIZE = 500; char buffer[BUFFER_SIZE]; DWORD bytesUsed{ 0 }; if (size.QuadPart == 0) { const static auto str = "Hello, world\r\n"; if (FALSE == WriteFile(win32fileHandle.Get(), str, strlen(str), &bytesUsed, nullptr)) ThrowWithGetLastError(L"Can't write to file"); sprintf_s(buffer, ARRAYSIZE(buffer), "Wrote %d bytes to file\r\n", bytesUsed); OutputDebugStringA(buffer); } else { if (FALSE == ReadFile(win32fileHandle.Get(), buffer, ARRAYSIZE(buffer) - 1, &bytesUsed, nullptr)) ThrowWithGetLastError(L"Can't read from file"); buffer[bytesUsed] = 0; OutputDebugStringA(buffer); } } // Trivial driver that gets a StorageFolder and then creates a file // inside it, writes some text, then re-opens it to read text. void TestWrapper() { using namespace Windows::Storage; using namespace Windows::Storage::Pickers; auto picker = ref new FolderPicker(); picker->FileTypeFilter->Append(L".txt"); picker->SuggestedStartLocation = PickerLocationId::Desktop; concurrency::create_task(picker->PickSingleFolderAsync()).then([] (StorageFolder^ folder) { if (folder != nullptr) { // Create and then read back a simple file Test(folder, L"win32handletest.txt", HANDLE_CREATION_OPTIONS::HCO_CREATE_ALWAYS); Test(folder, L"win32handletest.txt", HANDLE_CREATION_OPTIONS::HCO_OPEN_ALWAYS); } } ); } MainPage::MainPage() { InitializeComponent(); TestWrapper(); }