-
Notifications
You must be signed in to change notification settings - Fork 239
Win32 helpers
WIL Win32 helpers assist with various functions and data types used by Win32.
The Win32 helpers can be used by including the correct header file:
#include <wil/win32_helpers.h>
All string length constants are in the wil
namespace and have type size_t
.
Name | Value | Meaning |
---|---|---|
max_path_segment_length |
255 | Maximum length of a directory or file name. Does not include terminating null. |
max_path_length |
259 | Maximum length of a MAX_PATH path. Does not include terminating null. |
max_extended_path_length |
32743 | Maximum length of an extended path. Does not include terminating null. |
guid_string_buffer_length |
39 | Size of buffer to hold a GUID string, including enclosing curly braces and terminating null. |
guid_string_length |
38 | Length of a GUID string, including enclosing curly braces but not the terminating null. |
The unusual value for max_extended_path_length
comes from the system limit of 0x7FFF
minus 24, where 24 is the length of the \Device\HardDiskVolume#
prefix. If the path refers to the 10th through 99th hard disk volume, then the prefix grows to 25 characters, and the corresponding maximum length decreases by one.
The file time constants are in the wil::filetime_duration
namespace. They are all long long
and represent the number of FILETIME
units (100ns) contained in various well-known durations.
Name | Value |
---|---|
one_millisecond |
10000 |
one_second |
10000000 |
one_minute |
600000000 |
one_hour |
36000000000 |
one_day |
864000000000 |
The file time helpers are in the wil::filetime
namespace.
-
unsigned long long to_int64(const FILETIME &ft)
FILETIME from_int64(unsigned long long i64)
- The conversion functions convert between a
FILETIME
structure (two 32-bit integers) and a 64-bit unsigned integer.
- The conversion functions convert between a
-
FILETIME add(_In_ FILETIME const &ft, long long delta)
- Adjusts the value in an existing
FILETIME
structure by the specified number of ticks.
- Adjusts the value in an existing
-
bool is_empty(const FILETIME &ft)
- Returns
true
if theFILETIME
is all zeros.
- Returns
-
FILETIME get_system_time()
- Returns the system time as a
FILETIME
.
- Returns the system time as a
Many Win32 functions return a variable-sized string into a caller-provided buffer. The AdaptFixedSizeToAllocatedResult
template function implements the common pattern of requesting the string into a buffer, retrying with a larger buffer if needed.
template<typename string-type, size_t stackBufferLength = 256>
HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function<HRESULT(PWSTR, size_t, size_t*)> callback);
Calls the callback
repeatedly with larger and larger buffers until it is able to produce the desired string. The buffer is then returned in the form of a string_type
. Returns a COM error code on failure, in which case the result
is left unchanged.
-
string_type
can be any type supported by string_maker. -
stackBufferLength
is the size of the stack buffer used by the initial query. Choose a value that is likely to be sufficient for most use cases, since that provides the shorter execution path where no retry is needed. -
callback
retrieves the string into the provided buffer and returns the actual or required size. It is usually passed as a lambda.
HRESULT callback(PWSTR value, size_t valueLength, size_t* valueLengthNeededWithNul);
-
value
is a pointer to a buffer to be filled. -
valueLength
is the size of the buffer, including the space for the null terminator. -
valueLengthNeededWithNul
receives the required size of the buffer, including the space for the null terminator.
If the callback is able to read the entire string, then valueLengthNeededWithNul
receives the exact size of the result string (including the null terminator), and the callback returns S_OK
.
If the callback is not able to read the entire string due to the buffer being too small, then valueLengthNeededWithNul
receives the size of the buffer to be used for the next iteration, and the callback returns S_OK
. Most of the time, the Win32 function you are wrapping will give you a suggested size for the next iteration. Otherwise, you may need to use a heuristic, like (std::max)(40, valueLength * 2)
, but taking care to avoid integer overflow.
If the callback is unable to obtain the string at all, then it returns a COM error code, which is propagated as the return value from AdaptFixedSizeToAllocatedResult
. In this case, the value in valueLengthNeededWithNul
is not used.
Note: The parameters used by AdaptFixedSizeToAllocatedResult
do not follow the usual naming convention that Length
is the length without the null terminator, and Size
is the size including the null terminator. For that we apologize.
There is always a nonthrowing version of the adapter which returns an HRESULT
. There is often also a throwing version that returns the resulting string.
template<typename string_type, size_t stackBufferLength = 256>
HRESULT ExpandEnvironmentStringsW(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT;
template<typename string_type = wil::unique_cotaskmem_string, size_t stackBufferLength = 256>
string_type ExpandEnvironmentStringsW(_In_ PCWSTR input);
Wrapper around ExpandEnvironmentStringsW(input, buffer, bufferSize)
.
template<typename string_type, size_t stackBufferLength = 256>
HRESULT SearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, _In_opt_ PCWSTR extension, string_type& result) WI_NOEXCEPT;
template<typename string_type = unique_cotaskmem_string, size_t stackBufferLength = 256>
string_type TrySearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, PCWSTR _In_opt_ extension);
Wrapper around SearchPathW(path, fileName, extension, bufferSize, buffer, nullptr)
.
The TrySearchPathW
version treats ERROR_FILE_NOT_FOUND
as a success and produces an empty string.
template<typename string_type, size_t stackBufferLength = 256>
HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type& result) WI_NOEXCEPT;
Wrapper around QueryFullProcessImageNameW(processHandle, flags, buffer, &bufferSize)
.
template<typename string_type>
HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT;
template<typename string_type = unique_cotaskmem_string>
string_type GetEnvironmentVariableW(_In_ PCWSTR key);
template<typename string_type>
HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT;
template<typename string_type = unique_cotaskmem_string>
string_type TryGetEnvironmentVariableW(_In_ PCWSTR key);
Wrapper around GetEnvironmentVariableW(key, buffer, bufferSize)
.
The TryGetEnvironmentVariableW
version treats ERROR_ENVVAR_NOT_FOUND
as a success and produces an empty string.
template<typename string_type, size_t initialBufferLength = 128>
HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path);
template <typename string_type = unique_cotaskmem_string>
string_type GetModuleFileNameExW(HANDLE process, HMODULE module);
Wrapper around GetModuleFileNameExW(process, module, buffer, bufferSize)
.
template<typename string_type, size_t initialBufferLength = 128>
HRESULT GetModuleFileNameW(HMODULE module, string_type& path);
template<typename string_type = unique_cotaskmem_string>
string_type GetModuleFileNameW(HMODULE module);
template<typename string_type = unique_cotaskmem_string>
string_type GetModuleFileNameW(HMODULE module);
Wrapper around GetModuleFileNameExW(nullptr, module, buffer, bufferSize)
.
template<typename string_type, size_t stackBufferLength = 256>
HRESULT GetSystemDirectoryW(string_type& result) WI_NOEXCEPT;
Wrapper around GetSystemDirectoryW(buffer, bufferSize)
.
The one-time-initialization helper function performs an action the first time it is called, and does nothing on subsequent calls.
template<typename T>
HRESULT init_once_nothrow(_Inout_ INIT_ONCE& initOnce, T func, _Out_opt_ bool* callerCompleted = nullptr) WI_NOEXCEPT;
-
initOnce
is anINIT_ONCE
structure that records whether initialization has already occurred. -
func
is a functor which should have anHRESULT operator()
method. -
callerCompleted
is an optional parameter. If provided, it is set totrue
if thefunc
was invoked successfully, andfalse
if thefunc
was not invoked at all or if its invocation failed.
If func
returns a COM failure code, then that failure code is the return value of init_once_nothrow
and the initOnce
remains uninitialized. A subsequent call to init_one_nothrow
with the same initOnce
will attempt the initialization again.
Example:
INIT_ONCE g_init{};
ComPtr<IFoo> g_foo;
HRESULT MyMethod()
{
bool winner = false;
RETURN_IF_FAILED(wil::init_once_nothrow(g_init, []
{
ComPtr<IFoo> foo;
RETURN_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo));
RETURN_IF_FAILED(foo->Startup());
g_foo = foo;
return S_OK;
}, &winner));
if (winner)
{
RETURN_IF_FAILED(g_foo->Another());
}
return S_OK;
}
See InitOnceExecuteOnce on MSDN for more details.
template<typename T> bool init_once_failfast(_Inout_ INIT_ONCE& initOnce, T&& func) WI_NOEXCEPT;
The _failfast
version returns the callerCompleted
value and fails fast if the initialization function fails.
template<typename T> bool init_once(_Inout_ INIT_ONCE& initOnce, T func);
For the exception-based version, the func
should have a void operator()
, which reports failure by throwing an exception.
Example:
INIT_ONCE g_init{};
ComPtr<IFoo> g_foo;
void MyMethod()
{
bool winner = wil::init_once(g_init, []
{
ComPtr<IFoo> foo;
THROW_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo));
THROW_IF_FAILED(foo->Startup());
g_foo = foo;
});
if (winner)
{
THROW_IF_FAILED(g_foo->Another());
}
}
bool init_once_initialized(_Inout_ INIT_ONCE& initOnce) WI_NOEXCEPT;
Returns true
if the initOnce
structure has finished a successful initialization.
template<typename string_type, size_t stackBufferLength = 256>
HRESULT ExpandEnvAndSearchPath(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT;
Combination of ExpandEnvironmentStringsW
followed by SearchPathW
.
HINSTANCE GetModuleInstanceHandle();
Returns a handle to the current module. This uses the __ImageBase
special linker symbol.
auto GetProcAddressByFunctionDeclaration(hinst, FunctionName)
The GetProcAddressByFunctionDeclaration
macro provides type safety for GetProcAddress
by casting the return value to match the function prototype of the provided function.
Example:
auto sendMail = GetProcAddressByFunctionDeclaration(hinstMAPI, MAPISendMailW);
if (sendMail)
{
sendMail(0, 0, pmm, MAPI_USE_DEFAULT, 0);
}
The get_module_reference_for_thread()
method holds a reference to the module of its caller, and on destruction, frees the reference with FreeLibraryAndExitThread
. This prevents the OS from unloading the DLL while a worker thread is running.
Example:
wil::unique_handle myThread(::CreateThread(, [](auto&&...)
{
auto dllRef = wil::get_module_reference_for_thread();
// Do work here
// On destruction, dllRef calls FreeLibraryAndExitThread for you
}));
wil::WaitForDebuggerPresent()
can be used to stream line debugging workflows when the process being debugged is
not easily launched under the debugger. This includes processes launched by COM, or DLLs loaded in a surrogate process, remote debugging scenarios or processes launched with a special context that the debuggers launch feature can't re-create.
This behavior is controlled by a registry configuration
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<process file name>
WaitForDebuggerPresent=1
WaitForDebuggerPresent
is a REG_DWORD
value, when missing or 0
means "don't wait" (execute normally),
1
means wait for the debugger and continue execution once it is attached. 2
means wait for the debugger, break here once attached (useful for setting break points before execution begins).
An optional parameter useRegistryConfiguration
, when set to false
causes the code to unconditionally wait for the debugger and not require the registry configuration.