Share via


Manage Open Context (Compact 2013)

3/26/2014

Device drivers use open context to manage multiple open instances on a particular device. When an application calls CreateFile for a stream driver, the stream driver creates an open context. The open context is typically a pointer to a data structure that contains information about that open instance. The stream driver uses the open context to associate data pointers and other resources with an open instance.

For example, the following is a modified version of the stream driver SDT_Open function with additional code to create and return an open context.

// SDT_Open
// This function prepares the device driver for reading, writing,
// or both. It creates a context that is returned to an application.
// The application uses this context to call into the driver to
// perform reads and writes.
//
// The driver may optionally allocate a new context each time this
// function is called. This allows multiple applications to use
// the driver simultaneously. The driver is responsible for tracking
// all of the contexts that it creates so that it can deallocate
// them when Close or Deinit are called.
//
DWORD SDT_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
    DEBUGMSG(ZONE_INIT, 
        (TEXT("SDT_Open(): device context %x.\r\n"), hDeviceContext));

    // Return NULL if the device context is invalid:
    if ( !hDeviceContext )
    {
        DEBUGMSG(ZONE_OPEN|ZONE_ERROR,
            (TEXT("SDT_Open(): uninitalized device!\r\n)));
        SetLastError(ERROR_INVALID_HANDLE);
        return(NULL);
    }
    SDT_DEVICE_CONTEXT* pDevice = (SDT_DEVICE_CONTEXT *)hDeviceContext;

    //. . . . . . . . . . . . . . . . . . . . . . . . . .
    // Verify that the hardware can support this 
    // additional open instance.
    //. . . . . . . . . . . . . . . . . . . . . . . . . .
    
    // Allocate enough storage for this open context:

    SDT_OPEN_CONTEXT* pOpenContext = 
        (SDT_OPEN_CONTEXT *)LocalAlloc(LPTR, sizeof(SDT_OPEN_CONTEXT));

    // If allocation fails, set the error and return NULL:
    if (pOpenContext == NULL)
    {
        SetLastError(ERROR_OUTOFMEMORY);
        DEBUGMSG(ZONE_ERROR,
            (TEXT("SDT_Open(): cannot allocate memory!\r\n)));
        return(NULL);
    }

    //. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    // Initialize the pOpenContext structure here and
    // configure the hardware accordingly for this open instance.
    //. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

    // Use a critical section to protect the linked list of
    // open instances while you insert this instance into the list:
    EnterCriticalSection(&(pDevice->OpenCS));
    InsertHeadList(&pDevice->OpenList, pOpenContext);
    LeaveCriticalSection(&(pDevice->OpenCS));

    // Log a success message and return the open context:
    DEBUGMSG(ZONE_INIT, 
        (TEXT("SDT_Open(): open context %x.\r\n"), pOpenContext));
    return (DWORD) pOpenContext;
}

In this example, SDT_Open first checks that the device context the caller passes into the first parameter is valid. If the device context is not valid, SDT_Open signals an error and returns NULL. Because SDT_Init returns NULL if it is unable to create a device context, this validation of the passed-in device context is an important check to include in the SDT_Open function; the caller might simply pass the device context that is returned from SDT_Init without checking for errors.

After SDT_Open verifies that the hardware can support the additional open instance (a code sample is not included here because this verification is hardware-specific), it allocates an SDT_OPEN_CONTEXT structure to store information about the open instance. After configuring the hardware for this open operation and populating this structure with information about the open instance (again, these details are hardware-specific), it saves this open context in a linked list of open instances that are associated with that device. The critical section protects the linked list in case multiple threads call SDT_Open simultaneously. After InsertHeadList saves the open context in the list, SDT_Open returns it to the caller. Note that you don’t have to use a linked list here. You can choose a different data structure to save and locate your open contexts.

See Also

Concepts

Manage Device Driver Context