ConvertDateLogHandle

Reclassify a DATE_RANGE_HANDLE context into a DATE_LOG_HANDLE context

Overview

ConvertDateLogHandle verifies that the handle’s underlying file size is a valid multiple of DATE_RECORD_LENGTH and that it matches the date collection’s length exactly, then reclassifies the shared context’s magic number from __RANGE_LOG_MAGIC__ to __DATE_LOG_MAGIC__. All duplicate handles sharing this context are silently reclassified as well, since the magic number lives on the shared context, not on any individual handle.

Purpose

Used after a successful merge (for example by LoadDateLogHandle) to promote a provisional/merged range context into a verified, fully-fledged date log once its file contents have been confirmed consistent.

Key Features

Function Signature


HRESULT _Must_inspect_result_ _Success_(SUCCEEDED(return)) ConvertDateLogHandle(
    _Inout_ DATE_RANGE_HANDLE hDateRangeHandle,
    _In_    DWORD             dwFlags
);
Header note: datelog.h exports a related function named ConvertToDateLogHandle(hDateRangeHandle, hLastDate) that takes an optional DATE_ITEM_HANDLE hLastDate rather than a flags value. The signature above is the one documented for this page; the existing documentation does not explain the relationship between the two.

Parameters

hDateRangeHandle

[In, Out] DATE_RANGE_HANDLE

Handle whose shared context is reclassified on success.

  • NULL: not documented as accepted; always pass a valid, populated range handle
  • Type: must be a range handle (context magic __RANGE_LOG_MAGIC__) that holds a populated collection; other states fail validation as listed under Return Values
  • Ownership: the caller keeps ownership; the handle stays valid after the call (it is not consumed) and must still be closed with CloseDateLogHandle
  • Lifetime: must remain valid for the duration of the call. On success, the handle (and all duplicates) now behave as a date log
dwFlags

[In] DWORD

Behavior flags.

  • Pass DATE_CONVERT_INTERNAL (same value as DATE_RANGE_MERGE_INTERNAL) only when calling from within an already-locked internal context, to skip redundant locking
  • Otherwise pass 0

Return Values

S_OK

File size and collection length are consistent; the context was reclassified to __DATE_LOG_MAGIC__.

ERR_FILE_IS_CORRUPTED

File size is zero or not a multiple of DATE_RECORD_LENGTH.

ERR_INVALID_DATELOG_HANDLE

Date collection length is zero or exceeds DATE_LOG_MAX (0x591C8, 370,120 items).

ERR_MERGE_NO_COMPLETE

File size does not correspond exactly to the reported collection length.

ERR_INVALID_DATELOG_HANDLE and ERR_MERGE_NO_COMPLETE are documented in date_error.h. ERR_FILE_IS_CORRUPTED is also listed on LoadDateLogHandle but does not appear in the date_error.h reference page. When a check fails, the context is not reclassified.

Behavior and Operations

Lock (unless internal)
→
Validate file size
→
Validate length
→
Set DATE_LOG_MAGIC
→
Unlock

Resets dwCheckedMagic to 0 on the handle so subsequent lock operations re-verify the newly-set magic number rather than relying on a stale cached check.

Remarks

Thread Safety

Unless DATE_CONVERT_INTERNAL is passed, the function locks the handle for the duration of the call. Because the magic number is stored on the shared context, other threads holding duplicate handles observe the new classification once the call completes; they should not assume the type of a handle across a concurrent conversion.

Reference counting: the function does not add or remove references. The number of handles sharing the context is unchanged and each handle must still be closed exactly once with CloseDateLogHandle.

Ordering

Populate the range first (for example with LoadDateLogHandle, optionally followed by MergeDateLogHandle), then convert. Functions that require a date log handle, such as InitializeDateLogHandleOdbc, only accept the handle after it has been reclassified.

Ownership

The function does not allocate or free anything visible to the caller.

Relationship to Other Functions

Sample Code

The example creates a range handle, populates it with a generated range of market dates, promotes it with ConvertDateLogHandle, and reports each documented failure. Conversion checks the underlying file size, so it is intended for ranges backed by file content; a range with no file content is expected to report ERR_FILE_IS_CORRUPTED when the file size is zero. The sample frees every date item and closes both handles.


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

int main(void)
{
    HOLIDAYS_HANDLE  hHolidays = NULL;
    DATE_RANGE_HANDLE hRange   = NULL;
    DATE_ITEM_HANDLE hStart    = NULL;
    DATE_ITEM_HANDLE hEnd      = NULL;
    SYSTEMTIME       stStart   = { 0 };
    SYSTEMTIME       stEnd     = { 0 };
    FILETIME         ftStart   = { 0 };
    FILETIME         ftEnd     = { 0 };
    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;
    }

    stStart.wYear = 2024; stStart.wMonth = 1; stStart.wDay = 2;
    stEnd.wYear   = 2024; stEnd.wMonth   = 1; stEnd.wDay   = 31;
    if (!SystemTimeToFileTime(&stStart, &ftStart) || !SystemTimeToFileTime(&stEnd, &ftEnd)) {
        printf("SystemTimeToFileTime failed: %lu\n", GetLastError());
        goto cleanup;
    }

    /* A date range is a provisional collection: create one and populate it. */
    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, hHolidays, &hRange, HandleIsForRange);
    if (FAILED(hr)) {
        printf("InitializeDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    hr = InitializeDateItem(hRange, &ftStart, NULL, &hStart);
    if (SUCCEEDED(hr)) {
        hr = InitializeDateItem(hRange, &ftEnd, NULL, &hEnd);
    }
    if (SUCCEEDED(hr)) {
        hr = LoadDateLogHandle(NULL, hStart, hEnd, hRange, NULL, 0);
    }
    if (FAILED(hr)) {
        printf("Populating the range failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    /* Promote the range to a verified date log; pass 0 for an ordinary (unlocked) call. */
    hr = ConvertDateLogHandle(hRange, 0);
    if (SUCCEEDED(hr)) {
        printf("The range context is now a date log; collection length = %lu\n",
               (unsigned long)GetDateCollectionLength(hRange));
        rc = 0;
    }
    else if (hr == ERR_FILE_IS_CORRUPTED) {
        printf("File size is zero or not a multiple of DATE_RECORD_LENGTH.\n");
    }
    else if (hr == ERR_INVALID_DATELOG_HANDLE) {
        printf("The collection length is zero or exceeds DATE_LOG_MAX.\n");
    }
    else if (hr == ERR_MERGE_NO_COMPLETE) {
        printf("The file size does not match the collection length.\n");
    }
    else {
        printf("ConvertDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
    }

cleanup:
    FreeDateItem(hEnd);
    FreeDateItem(hStart);
    if (hRange != NULL && FAILED(CloseDateLogHandle(hRange))) {
        rc = 1;
    }
    if (FAILED(CloseDateLogHandle(hHolidays))) {
        rc = 1;
    }
    return rc;
}

See Also