When a new Windows version comes out, I’m always curious about the new Windows API (Win32) functions that are added to the release.
With Windows 8, things get a little more complicated, as there are desktop apps and there are metro apps. Now, for every Windows API function the documentation states whether this API is valid for desktop apps only or for desktop apps and metro apps.
One classic function is CreateFile. This is one of the oldest functions – exists since the very first Windows NT version. In Windows 8, it’s marked for desktop apps only. This may be understandable, as the Windows Runtime has other ways to use files, such as the StorageFile class. However, Windows 8 has a new function called CreateFile2. This one, in contrast to CreateFile, can be used in desktop and metro apps. Here’s its prototype:
- HANDLE WINAPI CreateFile2(
- _In_ LPCWSTR lpFileName,
- _In_ DWORD dwDesiredAccess,
- _In_ DWORD dwShareMode,
- _In_ DWORD dwCreationDisposition,
- _In_opt_ LPCREATEFILE2_EXTENDED_PARAMETERS pCreateExParams
- );
Here’s the prototype of CreateFile:
- HANDLE WINAPI CreateFile(
- __in LPCTSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
The first four arguments of CreateFile2 exist in both CreateFile and CreateFile2. The new extended parameters structure of CreateFile2 simply packages the “missing” arguments into an single optional structure:
- typedef struct _CREATEFILE2_EXTENDED_PARAMETERS {
- DWORD dwSize;
- DWORD dwFileAttributes;
- DWORD dwFileFlags;
- DWORD dwSecurityQosFlags;
- LPSECURITY_ATTRIBUTES lpSecurityAttributes;
- HANDLE hTemplateFile;
- } CREATEFILE2_EXTENDED_PARAMETERS, *PCREATEFILE2_EXTENDED_PARAMETERS, *LPCREATEFILE2_EXTENDED_PARAMETERS;
This structure actually adds nothing to what CreateFile can specify. The dwFlagsAndAttributes of CreateFile is logically split to three groups of flags represented by dwFileAttributes, dwFileFlags and dwSecurityQosFlags in this structure for CreateFile2. Although the split is a good thing, it doesn’t explain why CreateFile is forbidden in metro style apps. Furthermore, the documentation for CreateFile2 states that in metro apps this function can only open files and directories (and not things like pipes, mailslots, consoles, etc.).
So why is CreateFile forbidden in metro apps? Perhaps it does allow opening something that CreateFile2 forbids?
I decided to try calling it from a metro app. Trying to just use CreateFile would not compile, as a set of #ifdef/#endif is placed inside the Windows headers to prevent compiling a forbidden API. This, however, can be circumvented easily. We can just create the correct prototype manually:
- extern "C" {
- HANDLE WINAPI CreateFileW(
- __in LPCTSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
- }
This is just the CreateFile declaration from the docs wrapped in an extern “C” declaration; this is important, otherwise the liker would complain of an unresolved external (trying to look for C++ linkage). Also, note the function is declared as CreateFileW (the Unicode version) and not simply CreateFile, as CreateFile is actually a macro, and would not have been found by the linker.
Let’s add a simple call to this CreateFileW in a blank C++ metro style application in the BlankWindow constructor:
- HANDLE h = ::CreateFileW(L"C:\\Users\\Pavel\\Documents\\test.txt", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, 0);
- if(h == INVALID_HANDLE_VALUE) {
- auto err = ::GetLastError();
- }
- else
- ::CloseHandle(h);
This code tries to open a text file. This fails with error code 5 (access denied), as does CreateFile2. Although I set up the manifest with access to the documents library and set up a TXT file association, it refuses to work.
There doesn’t seem to be a noticeable difference between CreateFile and CreateFile2. I don’t understand at this time why CreateFile2 exists, apart from the convenience of that extra optional structure. There’s a room for further investigation, perhaps looking at NtDll.dll to see if these call different system services (unlikely, but worth a check).