What is the purpose of the win32 CreateFile2 api call? - winapi

They have added a new API call in windows 8 called CreateFile2 which as far as I can tell does exactly the same as the existing CreateFile function only it packages up its parameters somewhat differently.
What has been added to make this necessary, as I can't see anything in the documentation.

CreateFile actually can do a lot more than just open a file. CreateFile2 was created to both restrict the 'surface area' of the function to just the functionality allowed for UWP apps, -and- because the WACK tool can't really distinguish between 'good' use and 'bad' use of an import function, just that it is being used at all.
The typical pattern I use in my C++ libraries is as follows. I use an RAII pattern for the file handle to support when C++ Exception Handling is used (in addition to just being good modern C++ coding practice):
#include <assert.h>
#include <memory>
struct handle_closer
{ void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };
using ScopedHandle = std::unique_ptr<void, handle_closer>;
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
The reason I have safe_handle is because CreateFile and CreateFile2 are defined to return INVALID_HANDLE_VALUE (-1) instead of returning 0 for a failure. Most other Win32 functions that return handles return 0 for a failure, and I've confirmed that there's no case where a '0' is a valid Win32 handle.
For reading I use:
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(
CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
#else
ScopedHandle hFile(safe_handle(
CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
#endif
if (!hFile)
// Error
It is important to use FILE_SHARE_READ instead of 0 for the dwShareMode parameter for reading. UWP apps don't have exclusive read access to existing files, so calls would fail if you used 'exclusive' share mode (i.e. 0).
And for writing a file:
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(
CreateFile2(szFile, GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, nullptr)));
#else
ScopedHandle hFile(safe_handle(
CreateFileW(szFile, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, 0, nullptr)));
#endif
if (!hFile)
// Error!
For writing I request the DELETE permission because I use SetFileInformationByHandle with FILE_DISPOSITION_INFO to clean up if the file output process fails. See scoped.h.
See Dual-use Coding Techniques for Games for more information.

Due to the multiplexing of file creation flags, file attribute flags and
security QoS flags into a single DWORD (dwFlagsAndAttributes) parameter for
CreateFile, there is no way to add any more flags to CreateFile. Additional
flags for the create operation must be added to CreateFile2 only. For example FILE_FLAG_OPEN_REQUIRING_OPLOCK flag. This flag is documented FltCreateFile - kernel mode

Related

CreateFileW with \\?\ prefix and long file name returned INVALID_HANDLE_VALUE

#include <Windows.h>
#include <cassert>
int main()
{
auto h = CreateFileW(
LR"(\\?\C:\Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog.txt)",
GENERIC_READ | GENERIC_WRITE,
0,
nullptr,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL
);
assert(h != INVALID_HANDLE_VALUE);
CloseHandle(h);
}
What am I doing wrong here?
Project settings btw:
Running with admin doesn't solve the issue either. I am running windows 11 22621
You are running into an NTFS (presumably) limitation, where path components (including the file name) are limited to 255 UTF-16 code units. The file name you are supplying is 263 code units long, and you are getting an ERROR_INVALID_NAME error code ("The filename, directory name, or volume label syntax is incorrect.").
To solve this, you'll need to make the file name part no longer than 255 UTF-16 code units.

Mapping LARGE_INTEGER to SIZE_T in both 32-bit and 64-bit code

I'm trying to map a file to memory, and calc its hash:
// Declaration in header file which I don't control
void SymCryptSha256(PCBYTE pbData, SIZE_T cbData, PBYTE pbResult);
// MY code
HANDLE hFile = ::CreateFile(...);
HANDLE hMap = ::CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr));
byte* pMap = ::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
BYTE[64] hash;
ULARGE_INTEGER li;
li.LowPart = ::GetFileSize(file , &li.HighPart);
// This compiles in 64-bit, but errors in 32-bit:
// error C4244: 'argument': conversion from 'ULONGLONG' to 'SIZE_T', possible loss of data
::SymCryptSha256(pMap, li.QuadPart, &hash);
This is because SymCryptSha256's second argument is SIZE_T, which in 32-bit compilation is 32-bit. The desired behavior is:
64-bit: Use the entire size, which is li.QuadPart
32-bit: In case size>4GB, MapViewOfFile would fail anyways. So, just use li.LowPart.
Looks to me like I'll need to do this with #ifdefs - is there a more elegant way for it?
In the general case, and using this trick, you could do something like this:
if (li.QuadPart > ((ULONGLONG)((size_t)(-1))) too_big();
size_t result = (size_t)(li.QuadPart);
The compiler should optimize the first line into a no-op in a 64-bit compile.
(In your particular case, you probably don't need it anyway; the code will already have failed.)
Note: as already discussed in the comments, in this particular case it would be preferable, if at all possible, to use a hashing API that allows you to hash the data in chunks.

How does ShowWindow report failure?

Reading the documentation it looks like the ShowWindow function has no notion of failure. This surprises me since it seems that pretty much any non-trivial code can fail.
The window handle might be invalid. Clearly, that's a contact violation committed by the caller but is this case simply "undefined" or "don't care", then?
I wonder if SetLastError is supported.
While ShowWindow() indeed has no notion of error, we can use SetWindowPos() as an alternative that is documented to support GetLastError().
In the following I provide an example that shows how to wrap SetWindowPos() into a function to bridge the gap between C-style error reporting and the C++ way of doing it by throwing and handling an exception.
Example:
#include <windows.h>
#include <iostream>
#include <sstream>
#include <system_error>
// Show or hide the given window by calling SetWindowPos().
//
// \exception Reports any error by throwing std::sytem_error exception.
void MyShowWindow( HWND hwnd, bool show ) {
DWORD flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER;
if( show )
flags |= SWP_SHOWWINDOW;
else
flags |= SWP_HIDEWINDOW;
if( !::SetWindowPos( hwnd, nullptr, 0, 0, 0, 0, flags ) ) {
// NOTE: Call GetLastError() IMMEDIATELY when a function's return value indicates
// failure and it is documented that said function supports GetLastError().
// ANY other code (be it your own or library code) before the next line must be
// avoided as it may invalidate the last error value.
DWORD err = ::GetLastError();
std::ostringstream msg;
msg << "Could not change visibility of window (HWND 0x" << hwnd << ")";
throw std::system_error( static_cast<int>( err ), std::system_category(), msg.str() );
}
}
Usage:
When using the wrapper function MyShowWindow() you must make sure to catch the exceptions thrown by it. The following example shows how to do that.
int main(){
try{
// Passing an invalid handle to MyShowWindow() will throw
// std::system_error exception. There may be other reasons for the
// function to fail, for instance if you pass the window handle of
// another process to which you don't have access as an argument
// to the function.
HWND anInvalidHandle = 0;
MyShowWindow( anInvalidHandle, true );
}
catch( std::system_error& e ){
// Catch the exception thrown by MyShowWindow() and report all
// available error details.
// e.code() outputs the error code retrieved via GetLastError().
std::cout << "Error: " << e.what() << std::endl
<< "Error code: " << e.code() << std::endl;
}
return 0;
}
Output:
Error: Could not change visibility of window (HWND 0x00000000): Ung³ltiges Fensterhandle
Error code: system:1400
The message says "invalid window handle", the error code corresponds to ERROR_INVALID_WINDOW_HANDLE.
Note:
Although the provided MyShowWindow() function only supports SW_HIDE and SW_SHOW functionality of ShowWindow, the remaining functionality could propably be provided by using additional SetWindowPos flags (e. g. SW_SHOWNA maps to SWP_SHOWWINDOW | SWP_NOACTIVATE) or calling other Windows API functions that provide this functionality and are documented to support GetLastError().
ShowWindowAsync while asynchronous in nature, it does however tell you if the operation was started successfully or not. Depending on what you are doing, it might be a usable alternative.
ShowWindow does not have any error-awareness. If the window provided does not exist (or is not accessible), it just returns false.
ShowWindow in fact does not do much more than sending a WM_SHOW message to the targeted window. Because of the nature of the windows message queue, ShowWindow has no knowledge about its completion status. Although, as pointed out in the comments, WM_SHOW is handled synchronously, the message queue itself has no built-in error reporting mechanism aside from sending error messages back to the sender.
[edit]
It seems that GetLastError reports an invalid window handle when trying to access a non-existing window. To me, this is an unknown behaviour as normally a return value should indicate whether to use GetLastError or not. However, this can be easily avoided by testing for the window manually in advance (see: IsWindow)

mciSendString with Visual C++ - Parameters?

I am not a native C++ programmer, so I need some help with the following:
I got this code working:
#pragma comment(lib, "winmm.lib")
LPCWSTR openCDCommand = L"set cdaudio door open";
//comes from Windows.h, needs winmm.lib see header includes
int errCode = mciSendString(openCDCommand, 0, 0, 0);
Questions:
Do I need to work with LPCWSTR? Why didn't I find a System::String example?
How should I handle 'string concatination'? I cant simply do L"foo"+L"baar"?
Am I on the totally wrong way to play sounds with mciSendString? (actually I really want to use MCI Command and MCI sendString as i did in other projects before)
Is there another way to include the external function mciSendString so it can handle handles?
The signature of mciSendString is
MCIERROR mciSendString(
LPCTSTR lpszCommand,
LPTSTR lpszReturnString,
UINT cchReturn,
HANDLE hwndCallback);
So, regarding the first 2 parameters, in unicode it will be a wchar pointer and in multibyte it will be a char pointer. It's the signature. You cannot change that and you shouldn't worry about that.
std::wstring someString( L"Foo" );
someString.append( L"bar ");
I would play sound with core audio API, waveOut or maybe DirectSound. But, not with the mciSendString().
I'm afraid I don't understand this one.. can you explain it better?
This now works for me - took some time, but maybe in future this will help others:
#include "vcclr.h" // compile with /clr(!)
int Player::mciSendStringHandle(String ^ givenHandle)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(givenHandle);
return mciSendString(wch, 0, 0, 0);
}

SysInternal's WinObj device listing mechanism

SysInternals's WinObj can list all device objects.
I wonder how it can list the devices.
Is there any open source we can read?(or a code snippet)
What is the most significant function I should know?
WinObj uses the NT system calls NtOpenDirectoryObject and NtQueryDirectoryObject. There is no driver or kernel code needed. You won't see the imports because these NT functions are loaded via LoadLibrary/GetProcAddress.
You don't have to enumerate the entire object namespace. If you're interested in the device objects call NtOpenDirectoryObject with "\Device", then call NtQueryDirectoryObject on the returned handle.
According to SysInternals' web page:
The native NT API provides routines
that allow user-mode programs to
browse the namespace and query the
status of objects located there, but
the interfaces are undocumented.
I've tried looking at WinObj's import table (dumpbin /imports winobj.exe) but there are no obvious suspects :-(
As per the answer from user1575778 you can use NtOpenDirectoryObject and NtQueryDirectoryObject (which from user mode are identical to ZwOpenDirectoryObject and ZwQueryDirectoryObject respectively) to list the objects inside the object manager namespace.
Have a look at objmgr.hpp of NT Objects aka ntobjx, in particular at the class NtObjMgr::Directory (or DirectoryT). It provides the same functionality nicely wrapped into a C++ class. The whole utility is open source under a liberal license (dual-licensed due to WTL-use: MIT and MS-PL), so bits and pieces can be reused however you please, provided you comply with the license terms.
But here's a simple C++ code example catering just your use case:
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <winternl.h>
NTSTATUS (NTAPI* NtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS (NTAPI* NtQueryDirectoryObject)(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
VOID (NTAPI* RtlInitUnicodeString_)(PUNICODE_STRING, PCWSTR);
NTSTATUS (NTAPI* NtClose_)(HANDLE);
#define DIRECTORY_QUERY (0x0001)
#define DIRECTORY_TRAVERSE (0x0002)
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#endif // STATUS_SUCCESS
#ifndef STATUS_MORE_ENTRIES
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#endif // STATUS_MORE_ENTRIES
#ifndef STATUS_NO_MORE_ENTRIES
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#endif // STATUS_NO_MORE_ENTRIES
int PrintDevices()
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING objname;
HANDLE hDeviceDir = NULL;
RtlInitUnicodeString_(&objname, L"\\Device");
InitializeObjectAttributes(&oa, &objname, 0, NULL, NULL);
ntStatus = NtOpenDirectoryObject(&hDeviceDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &oa);
if(NT_SUCCESS(ntStatus))
{
size_t const bufSize = 0x10000;
BYTE buf[bufSize] = {0};
ULONG start = 0, idx = 0, bytes;
BOOLEAN restart = TRUE;
for(;;)
{
ntStatus = NtQueryDirectoryObject(hDeviceDir, PBYTE(buf), bufSize, FALSE, restart, &idx, &bytes);
if(NT_SUCCESS(ntStatus))
{
POBJECT_DIRECTORY_INFORMATION const pdilist = reinterpret_cast<POBJECT_DIRECTORY_INFORMATION>(PBYTE(buf));
for(ULONG i = 0; i < idx - start; i++)
{
if(0 == wcsncmp(pdilist[i].TypeName.Buffer, L"Device", pdilist[i].TypeName.Length / sizeof(WCHAR)))
{
_tprintf(_T("%s\n"), pdilist[i].Name.Buffer);
}
}
}
if(STATUS_MORE_ENTRIES == ntStatus)
{
start = idx;
restart = FALSE;
continue;
}
if((STATUS_SUCCESS == ntStatus) || (STATUS_NO_MORE_ENTRIES == ntStatus))
{
break;
}
}
(void)NtClose_(hDeviceDir);
return 0;
}
_tprintf(_T("Failed NtOpenDirectoryObject with 0x%08X"), ntStatus);
return 1;
}
int _tmain(int /*argc*/, _TCHAR** /*argv*/)
{
HMODULE hNtDll = ::GetModuleHandle(_T("ntdll.dll"));
*(FARPROC*)&NtOpenDirectoryObject = ::GetProcAddress(hNtDll, "NtOpenDirectoryObject");
*(FARPROC*)&NtQueryDirectoryObject = ::GetProcAddress(hNtDll, "NtQueryDirectoryObject");
*(FARPROC*)&RtlInitUnicodeString_ = ::GetProcAddress(hNtDll, "RtlInitUnicodeString");
*(FARPROC*)&NtClose_ = ::GetProcAddress(hNtDll, "NtClose");
if (!NtOpenDirectoryObject || !NtQueryDirectoryObject || !RtlInitUnicodeString_ || !NtClose_)
{
_tprintf(_T("Failed to retrieve ntdll.dll function pointers\n"));
return 1;
}
return PrintDevices();
}
Some remarks: This will not delve into subdirectories, it will not list any types other than Device and it will not resolve symbolic links, if any. For any of those features, please look at the aforementioned utility's source code and adjust as needed. winternl.h should be available in any recent Windows SDK.
The functions RtlInitUnicodeString_ and NtClose_ have a trailing underscore to avoid clashes with these native API functions, which are declared in winternl.h, but use __declspec(dllimport).
Disclosure: I am the author of ntobjx.
You can use NtOpenDirectoryObject and NtQueryDirectoryObject to enumarate the objects list in a given directory.
To get the details of the object namespace, you must use the Windows NT Undocumented API. That is also used by the WinObj as it is described here that how WinOBj getting the all results..and for those who are saying that we need a driver to do this please, read these lines on given page.
"One obvious way is to use a driver – in kernel mode everything is accessible – so the client app can get the required information by communicating with its own driver. WinObj does not use a driver, however (this is one reason it’s able to execute without admin privileges, although with admin privileges it shows all objects as opposed to partial results)."
You can start with SetupDiCreateDeviceInfoList and use other related functions to enumerate all the devices. This stuff is painful to use.

Resources