Validate a DATE_LOG_HANDLE, DATE_RANGE_HANDLE, or HOLIDAYS_HANDLE
IsValidDateLogHandle performs a full validate-lock-unlock cycle on the given handle (via ValidateAndLockDateLogHandle() and UnlockValidatedDateLogHandle()) purely to determine whether the handle is currently well-formed, without performing any other work.
The function works for every collection handle type declared in datelog.h: DATE_LOG_HANDLE, DATE_RANGE_HANDLE and HOLIDAYS_HANDLE. It is intended as a cheap sanity check at API boundaries, for example before storing a handle, after receiving one from another component, or before an operation whose failure would be expensive to undo.
ERR_BAD_HANDLE_TYPE / ERR_INVALID_DATELOG_HANDLE results of other functions) when the type matters.TRUE result means the handle was valid at the moment of the check. It does not prevent another thread from closing or invalidating the handle immediately afterwards.BOOL; no HRESULT and no reason for failure are reported.
BOOL _Check_return_ IsValidDateLogHandle(
_In_ DATE_COLLECTION_HANDLE hDateLogHandle
);
This declaration matches the one in datelog.h.
[In] DATE_COLLECTION_HANDLE
Handle to validate.
DATE_LOG_HANDLE, DATE_RANGE_HANDLE or HOLIDAYS_HANDLE returned by InitializeDateLogHandle, DuplicateDateLogHandle or GetDateLogHolidayHandle.FALSE is returned.CloseDateLogHandle; the handle is invalid after closing and its memory may no longer be readable.| Value | Condition |
|---|---|
TRUE | The handle passed validation and the lock/unlock cycle completed successfully. |
FALSE | hDateLogHandle is NULL, validation fails, or unlocking fails. |
The function returns BOOL, not HRESULT. For the corresponding library error codes see ERR_INVALID_DATELOG_HANDLE (“the date log or range handle is invalid”) and ERR_INVALID_HOLIDAY_HANDLE in date_error.h; those are returned by functions that take a handle and report an HRESULT.
Because the handle is locked while it is validated, the check participates in the library’s normal synchronization: if the handle cannot be locked or unlocked, the function returns FALSE.
The validate-lock-unlock cycle makes the check itself safe to call while other threads use handles that share the same context. The answer is only a snapshot: a handle that is valid when this function returns may be closed by another thread before your next call. Do not use IsValidDateLogHandle as a substitute for correct handle ownership.
CloseDateLogHandle does not invalidate other handles created with DuplicateDateLogHandle.CloseDateLogHandle returns, the handle is invalid (_Post_invalid_) and must not be passed to this function; set your variable to NULL after closing so that a later check reliably returns FALSE.ERR_DATE_LOG_RESTORE_FAILED, the date log context is marked invalid and the handle is unusable (see MergeDateLogHandle and date_error.h); close it and re-create it from its data source.ERR_INVALID_DATELOG_HANDLE or return FALSE/NULL themselves.IsDateLogHandleUpToDate, IsDateItemHoliday, IsDateItemCoveredByHolidaysHandle and DateLogHandleHasChanged report FALSE (or -1) when validation fails, which is indistinguishable from other negative answers; validate first when you need to tell them apart.InitializeDateLogHandleDuplicateDateLogHandleCloseDateLogHandleGetDateLogHolidayHandleIsDateLogHandleUpToDateDateLogHandleHasChangedMergeDateLogHandleThe sample validates a NULL handle, a holidays handle, a date log, a date range, the log’s own holidays handle and a duplicate handle. It then closes the original log, sets the variable to NULL, and shows that the duplicate stays valid. Every handle that was created is closed exactly once on every path.
#include <Windows.h>
#include <stdio.h>
#include "datelog.h"
static BOOL MakeFileTime(WORD wYear, WORD wMonth, WORD wDay, PFILETIME pFt)
{
SYSTEMTIME st = { 0 };
st.wYear = wYear;
st.wMonth = wMonth;
st.wDay = wDay;
return SystemTimeToFileTime(&st, pFt);
}
/* Creates a holidays handle and loads it with the range [first, last]. */
static HRESULT BuildHolidays(PFILETIME pFirst, PFILETIME pLast, HOLIDAYS_HANDLE *phHolidays)
{
HRESULT hr = S_OK;
HOLIDAYS_HANDLE hHolidays = NULL;
DATE_ITEM_HANDLE hFirst = NULL;
DATE_ITEM_HANDLE hLast = NULL;
*phHolidays = NULL;
hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, NULL, &hHolidays, HandleIsForHolidays);
if (FAILED(hr)) goto cleanup;
hr = InitializeDateItem(hHolidays, pFirst, NULL, &hFirst);
if (FAILED(hr)) goto cleanup;
hr = InitializeDateItem(hHolidays, pLast, NULL, &hLast);
if (FAILED(hr)) goto cleanup;
hr = LoadDateLogHandle(NULL, hFirst, hLast, hHolidays, NULL, 0);
if (FAILED(hr)) goto cleanup;
*phHolidays = hHolidays;
hHolidays = NULL;
cleanup:
FreeDateItem(hLast);
FreeDateItem(hFirst);
if (hHolidays != NULL) {
(void)CloseDateLogHandle(hHolidays);
}
return hr;
}
/* Creates a date log or range handle of the given type and generates [first, last] into it. */
static HRESULT BuildCollection(HOLIDAYS_HANDLE hHolidays, DateHandleType type,
PFILETIME pFirst, PFILETIME pLast, DATE_LOG_HANDLE *phCollection)
{
HRESULT hr = S_OK;
DATE_LOG_HANDLE hCollection = NULL;
DATE_ITEM_HANDLE hFirst = NULL;
DATE_ITEM_HANDLE hLast = NULL;
*phCollection = NULL;
hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, hHolidays, &hCollection, type);
if (FAILED(hr)) goto cleanup;
hr = InitializeDateItem(hHolidays, pFirst, NULL, &hFirst);
if (FAILED(hr)) goto cleanup;
hr = InitializeDateItem(hHolidays, pLast, NULL, &hLast);
if (FAILED(hr)) goto cleanup;
hr = LoadDateLogHandle(NULL, hFirst, hLast, hCollection, NULL, 0);
if (FAILED(hr)) goto cleanup;
*phCollection = hCollection;
hCollection = NULL;
cleanup:
FreeDateItem(hLast);
FreeDateItem(hFirst);
if (hCollection != NULL) {
(void)CloseDateLogHandle(hCollection);
}
return hr;
}
static const char *Describe(BOOL bValid)
{
return bValid ? "valid" : "NOT valid";
}
int main(void)
{
int exitCode = 1;
HRESULT hr = S_OK;
FILETIME ftFirst = { 0 };
FILETIME ftLast = { 0 };
HOLIDAYS_HANDLE hHolidays = NULL;
DATE_LOG_HANDLE hDateLog = NULL;
DATE_LOG_HANDLE hRange = NULL;
DATE_LOG_HANDLE hDuplicate = NULL;
HOLIDAYS_HANDLE hLogHolidays = NULL;
if (!MakeFileTime(2025, 1, 2, &ftFirst) || !MakeFileTime(2025, 3, 31, &ftLast)) {
printf("Invalid calendar date.\n");
return 1;
}
/* NULL is reported as invalid rather than crashing. */
printf("NULL handle: %s\n", Describe(IsValidDateLogHandle(NULL)));
hr = BuildHolidays(&ftFirst, &ftLast, &hHolidays);
if (FAILED(hr)) {
printf("BuildHolidays failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
printf("Holidays handle: %s\n", Describe(IsValidDateLogHandle(hHolidays)));
hr = BuildCollection(hHolidays, HandleIsForDatelog, &ftFirst, &ftLast, &hDateLog);
if (FAILED(hr)) {
printf("BuildCollection (date log) failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
printf("Date log handle: %s\n", Describe(IsValidDateLogHandle(hDateLog)));
hr = BuildCollection(hHolidays, HandleIsForRange, &ftFirst, &ftLast, &hRange);
if (FAILED(hr)) {
printf("BuildCollection (range) failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
printf("Date range handle: %s\n", Describe(IsValidDateLogHandle(hRange)));
hLogHolidays = GetDateLogHolidayHandle(hDateLog);
if (hLogHolidays != NULL) {
printf("Log's holidays handle: %s\n", Describe(IsValidDateLogHandle(hLogHolidays)));
}
hr = DuplicateDateLogHandle(hDateLog, &hDuplicate);
if (FAILED(hr)) {
printf("DuplicateDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
/* Closing one handle leaves the duplicate, which shares the same context, valid. */
hr = CloseDateLogHandle(hDateLog);
if (FAILED(hr)) {
printf("CloseDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
hDateLog = NULL;
printf("Closed handle (now NULL): %s\n", Describe(IsValidDateLogHandle(hDateLog)));
printf("Duplicate handle: %s\n", Describe(IsValidDateLogHandle(hDuplicate)));
exitCode = 0;
cleanup:
if (hDuplicate != NULL) {
(void)CloseDateLogHandle(hDuplicate);
}
if (hLogHolidays != NULL) {
(void)CloseDateLogHandle(hLogHolidays);
}
if (hRange != NULL) {
(void)CloseDateLogHandle(hRange);
}
if (hDateLog != NULL) {
(void)CloseDateLogHandle(hDateLog);
}
if (hHolidays != NULL) {
(void)CloseDateLogHandle(hHolidays);
}
return exitCode;
}