IsValidDateLogHandle

Validate a DATE_LOG_HANDLE, DATE_RANGE_HANDLE, or HOLIDAYS_HANDLE

Overview

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.

Key Points

Function Signature


BOOL _Check_return_ IsValidDateLogHandle(
    _In_ DATE_COLLECTION_HANDLE hDateLogHandle
);

This declaration matches the one in datelog.h.

Parameters

hDateLogHandle

[In] DATE_COLLECTION_HANDLE

Handle to validate.

  • Direction: input only; the handle is not changed.
  • Valid values: a DATE_LOG_HANDLE, DATE_RANGE_HANDLE or HOLIDAYS_HANDLE returned by InitializeDateLogHandle, DuplicateDateLogHandle or GetDateLogHolidayHandle.
  • NULL: allowed in the sense that it is detected and reported; FALSE is returned.
  • Ownership / lifetime: remains owned by the caller. The function neither closes nor retains the handle. Do not pass a handle that has already been closed with CloseDateLogHandle; the handle is invalid after closing and its memory may no longer be readable.

Return Values

ValueCondition
TRUEThe handle passed validation and the lock/unlock cycle completed successfully.
FALSEhDateLogHandle 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.

Behavior and Operations

ValidateAndLockDateLogHandle→UnlockValidatedDateLogHandle

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.

Remarks

Thread Safety

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.

Handle Lifetime and Ownership

Ordering and Related Functions

See Also

Sample Code

The 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;
}