How can I get Win32 HANDLE for StorageFile or StorageFolder in UWP?

I know that I can use Win32 APIs to access files in my own local data folder (for example, see this answer to a question ), but I need to access files outside of my application (for example, from an image library) and the libraries I'm trying to use are based on a Win32 HANDLE file and / or rely on the use of relative file names.

Since the only way to retrieve files in the Image Library (or retrieve files / folders returned by the collector) through StorageFile objects, how can I reuse my existing code? Do I have to rewrite everything to be asynchronous and rely on WinRT storage APIs?

+6
source share
1 answer

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 // These are copied from WindowsStorageCOM.h // You can remove this header file once the real file has been updated // to fix the WINAPI_PARTITION_DESKTOP block typedef interface IOplockBreakingHandler IOplockBreakingHandler; typedef interface IStorageItemHandleAccess IStorageItemHandleAccess; typedef interface IStorageFolderHandleAccess IStorageFolderHandleAccess; #ifdef __cplusplus extern "C" { #endif typedef /* [v1_enum] */ enum HANDLE_OPTIONS { HO_NONE = 0, HO_OPEN_REQUIRING_OPLOCK = 0x40000, HO_DELETE_ON_CLOSE = 0x4000000, HO_SEQUENTIAL_SCAN = 0x8000000, HO_RANDOM_ACCESS = 0x10000000, HO_NO_BUFFERING = 0x20000000, HO_OVERLAPPED = 0x40000000, HO_WRITE_THROUGH = 0x80000000 } HANDLE_OPTIONS; DEFINE_ENUM_FLAG_OPERATORS(HANDLE_OPTIONS); typedef /* [v1_enum] */ enum HANDLE_ACCESS_OPTIONS { HAO_NONE = 0, HAO_READ_ATTRIBUTES = 0x80, HAO_READ = 0x120089, HAO_WRITE = 0x120116, HAO_DELETE = 0x10000 } HANDLE_ACCESS_OPTIONS; DEFINE_ENUM_FLAG_OPERATORS(HANDLE_ACCESS_OPTIONS); typedef /* [v1_enum] */ enum HANDLE_SHARING_OPTIONS { HSO_SHARE_NONE = 0, HSO_SHARE_READ = 0x1, HSO_SHARE_WRITE = 0x2, HSO_SHARE_DELETE = 0x4 } HANDLE_SHARING_OPTIONS; DEFINE_ENUM_FLAG_OPERATORS(HANDLE_SHARING_OPTIONS); typedef /* [v1_enum] */ enum HANDLE_CREATION_OPTIONS { HCO_CREATE_NEW = 0x1, HCO_CREATE_ALWAYS = 0x2, HCO_OPEN_EXISTING = 0x3, HCO_OPEN_ALWAYS = 0x4, HCO_TRUNCATE_EXISTING = 0x5 } HANDLE_CREATION_OPTIONS; EXTERN_C const IID IID_IOplockBreakingHandler; MIDL_INTERFACE("826ABE3D-3ACD-47D3-84F2-88AAEDCF6304") IOplockBreakingHandler : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE OplockBreaking(void) = 0; }; EXTERN_C const IID IID_IStorageItemHandleAccess; MIDL_INTERFACE("5CA296B2-2C25-4D22-B785-B885C8201E6A") IStorageItemHandleAccess : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Create( /* [in] */ HANDLE_ACCESS_OPTIONS accessOptions, /* [in] */ HANDLE_SHARING_OPTIONS sharingOptions, /* [in] */ HANDLE_OPTIONS options, /* [optional][in] */ __RPC__in_opt IOplockBreakingHandler *oplockBreakingHandler, /* [system_handle][retval][out] */ __RPC__deref_out_opt HANDLE *interopHandle) = 0; }; EXTERN_C const IID IID_IStorageFolderHandleAccess; MIDL_INTERFACE("DF19938F-5462-48A0-BE65-D2A3271A08D6") IStorageFolderHandleAccess : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Create( /* [string][in] */ __RPC__in_string LPCWSTR fileName, /* [in] */ HANDLE_CREATION_OPTIONS creationOptions, /* [in] */ HANDLE_ACCESS_OPTIONS accessOptions, /* [in] */ HANDLE_SHARING_OPTIONS sharingOptions, /* [in] */ HANDLE_OPTIONS options, /* [optional][in] */ __RPC__in_opt IOplockBreakingHandler *oplockBreakingHandler, /* [system_handle][retval][out] */ __RPC__deref_out_opt HANDLE *interopHandle) = 0; }; #ifdef __cplusplus } #endif 

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(); } 
+14
source

Source: https://habr.com/ru/post/1265463/


All Articles