CloseDateLogHandle

Release all resources associated with a DATE_LOG_HANDLE

Overview

CloseDateLogHandle releases a DATE_LOG_HANDLE, DATE_RANGE_HANDLE, or HOLIDAYS_HANDLE previously obtained from InitializeDateLogHandle or DuplicateDateLogHandle. Because multiple handles may share one underlying context (via duplication), the function uses a reference-counting model: each call releases exactly one handle, and the shared context (the date log core, the holidays handle, and any ODBC connections) is freed only when the last handle referencing it is closed.

Purpose

Provides deterministic, thread-safe teardown of date log, range, and holidays handles, ensuring that shared resources (mutexes, critical sections, ODBC connection lists, and the date item array) are released exactly once, even when handles are duplicated and closed concurrently from multiple threads.

Key Features

Function Signature


HRESULT _Success_(SUCCEEDED(return)) CloseDateLogHandle(
    _In_ _Post_invalid_ DATE_LOG_HANDLE hDateLogHandle
);

Calling Convention

Standard C calling convention with SAL annotations for parameter validation and return value inspection. The function is declared in datelog.h.

Parameters

hDateLogHandle

[In] DATE_LOG_HANDLE

The handle to close. It may be a date log, date range, or holidays handle (all are opaque void* typedefs; see datelog.h).

  • Source: must have been obtained from InitializeDateLogHandle or DuplicateDateLogHandle
  • NULL: not allowed; a NULL handle is rejected with HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
  • Ownership: the caller owns each handle it receives and must close each one exactly once; closing releases only that handle’s reference
  • Lifetime: marked _Post_invalid_ — the handle must not be used after the call; set your variable to NULL
  • Lock state: must not currently be locked/in-use by any thread, including the calling thread

Return Values

Success Cases

S_OK (0x00000000)

The handle was released; if it was the last reference to its context, the shared context was freed as well.

Error Cases

HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)

hDateLogHandle is NULL.

HRESULT_FROM_WIN32(ERROR_TIMEOUT)

Timed out (5 seconds) waiting to acquire the handle’s own mutex.

HRESULT_FROM_WIN32(ERROR_ABANDONED_WAIT_0)

The handle’s mutex was abandoned by another thread.

HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE)

The internal lock state or context pointer is invalid/NULL.

HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE_STATE)

The handle is currently locked/in-use by another thread (lock-state fields are non-zero).

Always test the result with FAILED()/SUCCEEDED(). The documentation does not specify whether a handle remains valid after a failing return, so do not reuse it.

Behavior and Operations

Execution Flow

Acquire Handle Mutex
→
Acquire Context Mutex
→
Decrement Reference Count
→
Free Context If Last Reference
→
Free Local Handle

Reference Counting

Each shared DATE_CONTEXT tracks uiHandles, which is incremented by DuplicateDateLogHandle and decremented here. Only when the count reaches zero are the date log core, ODBC connection internals, and holidays handle actually freed.

ODBC Cleanup

If the context owns ODBC connection internals (pConnInternals), every connection node is flushed from its internal SLIST and each underlying ODBC_CONNECTION_HANDLE is released via FreeOdbcConnectionContext() before the connection list header itself is freed. Connections created with ConnectDateLogHandleToOdbcDatabase are therefore closed automatically; no separate disconnect call is required.

Resource Cleanup

Performed regardless of the success/failure of the context-free step:

Remarks

Thread Safety

The function acquires the handle’s mutex and then the shared context’s mutex, so closing duplicated handles from different threads is safe. It must not be called while the handle is locked by ValidateAndLockDateLogHandle(); doing so returns HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE_STATE). The call must also not race with other calls that use the same handle: once you have called CloseDateLogHandle on a handle, no thread may use it.

Handle Lifetime and Reference Counting

Recursive Closure: Closing the last handle referencing a date log/range context also recursively closes the associated holidays handle via an internal call to this same function.
Date items: standalone date items (from InitializeDateItem or GetDateItemCopy) are allocated independently of the log and are released with FreeDateItem, not by this function. Items that still point into a log’s core are freed with the core and must not be used after the last handle for that log is closed.

Sample Code

The following example creates a holidays handle and a date log, duplicates the date log, and then closes every handle it obtained, checking each result.


#include <stdio.h>
#include "datelog.h"

int main(void)
{
    HOLIDAYS_HANDLE hHolidays = NULL;
    DATE_LOG_HANDLE hDateLog  = NULL;
    DATE_LOG_HANDLE hWorker   = NULL;
    HRESULT         hr        = E_FAIL;
    int             rc        = 1;

    /* Holidays handle. Populate it with your market holiday data (see
       LoadDateLogHandle) before building date logs; that step is application specific. */
    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, NULL, &hHolidays, HandleIsForHolidays);
    if (FAILED(hr)) {
        printf("InitializeDateLogHandle failed for holidays: 0x%08lX\n", (unsigned long)hr);
        return 1;
    }

    /* hHolidays is duplicated internally by InitializeDateLogHandle, so the
       caller keeps (and must close) its own reference. */
    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, hHolidays, &hDateLog, HandleIsForDatelog);
    if (FAILED(hr)) {
        printf("InitializeDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup_holidays;
    }

    /* A duplicate shares the same context; the reference count is now 2. */
    hr = DuplicateDateLogHandle(hDateLog, &hWorker);
    if (FAILED(hr)) {
        printf("DuplicateDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup_log;
    }

    /* Closing the duplicate only decrements the count; hDateLog stays usable. */
    hr = CloseDateLogHandle(hWorker);
    hWorker = NULL;
    if (FAILED(hr)) {
        printf("CloseDateLogHandle failed for duplicate: 0x%08lX\n", (unsigned long)hr);
        goto cleanup_log;
    }

    rc = 0;

cleanup_log:
    /* Closing the last handle referencing the context frees the shared context. */
    hr = CloseDateLogHandle(hDateLog);
    hDateLog = NULL;
    if (FAILED(hr)) {
        printf("CloseDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
        rc = 1;
    }

cleanup_holidays:
    hr = CloseDateLogHandle(hHolidays);
    hHolidays = NULL;
    if (FAILED(hr)) {
        printf("CloseDateLogHandle failed for holidays: 0x%08lX\n", (unsigned long)hr);
        rc = 1;
    }
    return rc;
}

See Also