Release all resources associated with a DATE_LOG_HANDLE
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.
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.
HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE_STATE))
HRESULT _Success_(SUCCEEDED(return)) CloseDateLogHandle(
_In_ _Post_invalid_ DATE_LOG_HANDLE hDateLogHandle
);
Standard C calling convention with SAL annotations for parameter validation and return value inspection. The function is declared in datelog.h.
[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).
HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)_Post_invalid_ — the handle must not be used after the call; set your variable to NULLThe handle was released; if it was the last reference to its context, the shared context was freed as well.
hDateLogHandle is NULL.
Timed out (5 seconds) waiting to acquire the handle’s own mutex.
The handle’s mutex was abandoned by another thread.
The internal lock state or context pointer is invalid/NULL.
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.
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.
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.
Performed regardless of the success/failure of the context-free step:
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.
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;
}