Sample Code

Windows Driver Samples/ Near-Field Proximity Sample Driver (UMDF Version 1)/ C++/ driver/ FileContext.cpp/

/*++

Copyright (C) Microsoft Corporation, All Rights Reserved

Module Name:

    filecontext.cpp

Abstract:

    This file implements the class for context associated with the file object 

Environment:

    user mode only

Revision History:

--*/
#include "internal.h"

#include "FileContext.tmh"

CFileContext::~CFileContext()
{
    MethodEntry("void");
    
    while (!IsListEmpty(&m_SubscribedMessageQueue))
    {
        delete CMyPayload::FromListEntry(RemoveHeadList(&m_SubscribedMessageQueue));
    }
    
    if (m_pszType != NULL)
    {
        delete [] m_pszType;
        m_pszType = NULL;
    }

    if (m_pConnection != NULL)
    {
        delete m_pConnection;
        m_pConnection = NULL;
    }
    
    m_pWdfFile = NULL;

    EnterCriticalSection(&m_RoleLock);
    CompleteRequest(E_ABORT, 0, true);
    LeaveCriticalSection(&m_RoleLock);
    
    DeleteCriticalSection(&m_RoleLock);

    MethodReturnVoid();
}

HRESULT
CFileContext::Disable()
{
    MethodEntry("void");
    
    EnterCriticalSection(&m_RoleLock);
    
    HRESULT hr = S_OK;
    if ((m_Role == ROLE_UNDEFINED) || (m_Role == ROLE_PROXIMITY))
    {
        // Only Pub/Sub handles can be disabled
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }

    if (!m_fEnabled)
    {
        // Already disabled
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }

    if (SUCCEEDED(hr))
    {
        m_fEnabled = FALSE;

        CompleteRequest(HRESULT_FROM_NT(STATUS_CANCELLED), 0, true);

        // Purge all already received payloads
        while (!IsListEmpty(&m_SubscribedMessageQueue))
        {
            delete CMyPayload::FromListEntry(RemoveHeadList(&m_SubscribedMessageQueue));
        }
    }
    
    LeaveCriticalSection(&m_RoleLock);
    
    MethodReturnHR(hr);
}

HRESULT
CFileContext::Enable()
{
    MethodEntry("void");
    
    EnterCriticalSection(&m_RoleLock);
    
    HRESULT hr = S_OK;
    if ((m_Role == ROLE_UNDEFINED) || (m_Role == ROLE_PROXIMITY))
    {
        // Only Pub/Sub handles can be enabled
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }

    if (m_fEnabled)
    {
        // Already enabled
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }

    if (SUCCEEDED(hr))
    {
        m_fEnabled = TRUE;
    }
        
    LeaveCriticalSection(&m_RoleLock);
    
    MethodReturnHR(hr);
}

HRESULT
CFileContext::SetType(_In_ PCWSTR pszType)
{
    MethodEntry("pszType = '%S'", pszType);
    
    HRESULT hr = S_OK;
    WUDF_SAMPLE_DRIVER_ASSERT(m_pszType == NULL);
    
    SIZE_T cchStr = wcslen(pszType) + 1;
    if ((cchStr > MinCchType) && (cchStr < MaxCchType))
    {
        m_pszType = new WCHAR[cchStr];
        if (m_pszType != NULL)
        {
            hr = StringCchCopy(m_pszType, cchStr, pszType);
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }
    }
    else
    {
        hr = E_INVALIDARG;
    }

    MethodReturnHR(hr);
}

#define STATUS_BUFFER_TOO_SMALL 0xC0000023L
#define STATUS_BUFFER_OVERFLOW  0x80000005L


bool
CFileContext::CompleteOneGetNextSubscribedMessage(
    _In_                       DWORD cbPayload,
    _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload
    )
/*
 * m_RoleLock must already be acquired
 */
{
    MethodEntry("cbPayload = 0x%d",
          (DWORD)cbPayload);
    
    WUDF_SAMPLE_DRIVER_ASSERT(m_pWdfRequest != NULL);

    bool fDelivered = false;
    IWDFMemory* pWdfOutputMemory;
    m_pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
    if (pWdfOutputMemory != NULL)
    {
        SIZE_T cbOutputBuffer = 0;
        // Set the first 4 bytes as the size of the payload as a hint for future
        // subscriptions.
        HRESULT hr = pWdfOutputMemory->CopyFromBuffer(0, &cbPayload, 4);
        if (SUCCEEDED(hr))
        {
            cbOutputBuffer = 4;
            if (pbPayload != NULL)
            {
                if (pWdfOutputMemory->GetSize() < (cbPayload + 4))
                {
                    // We are unable to copy the payload into the output memory,
                    // Returning this signals to the client to send a bigger buffer
                    hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW);
                }
                else
                {
                    hr = pWdfOutputMemory->CopyFromBuffer(4, pbPayload, cbPayload);
                }
            }
            
            if (SUCCEEDED(hr))
            {
                fDelivered = true;
                cbOutputBuffer += cbPayload;
                if (m_dwQueueSize > 0)
                {
                    m_dwQueueSize--;
                }
            } 
        } 
        pWdfOutputMemory->Release();
        
        if (!CompleteRequest(hr, cbOutputBuffer, true))
        {
            fDelivered = false;
        }
    }

    MethodReturnBool(fDelivered);
}

HRESULT
CFileContext::GetNextSubscribedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest)
{
    MethodEntry("...");
    
    EnterCriticalSection(&m_RoleLock);

    HRESULT hr = S_OK;
    if (m_pWdfRequest != NULL)
    {
        // Only one pended request at a time allowed
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }
    
    if (!m_fEnabled)
    {
        // The handle is disabled
        hr = HRESULT_FROM_NT(HRESULT_FROM_NT(STATUS_CANCELLED));
    }

    if (SUCCEEDED(hr))
    {
        IWDFMemory* pWdfInputMemory;
        pWdfRequest->GetInputMemory(&pWdfInputMemory);
        SIZE_T cbInput;
        if (pWdfInputMemory->GetDataBuffer(&cbInput) == NULL)
        {
            if (m_Role == ROLE_SUBSCRIPTION)
            {
                m_pWdfRequest = pWdfRequest;
                m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread

                if ((m_pWdfRequest != NULL) && !IsListEmpty(&m_SubscribedMessageQueue))
                {
                    CMyPayload* pMyPayload = 
                        CMyPayload::FromListEntry(m_SubscribedMessageQueue.Flink);

                    if (CompleteOneGetNextSubscribedMessage(pMyPayload->GetSize(), 
                                                            pMyPayload->GetPayload()))
                    {
                        RemoveHeadList(&m_SubscribedMessageQueue);
                        delete pMyPayload;
                    }
                }
            }
            else if (m_Role == ROLE_ARRIVEDSUBSCRIPTION)
            {
                m_pWdfRequest = pWdfRequest;
                m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread
                if (m_pWdfRequest != NULL)
                {
                    CompleteOneArrivalEvent();
                }
            }
            else if (m_Role == ROLE_DEPARTEDSUBSCRIPTION)
            {
                m_pWdfRequest = pWdfRequest;
                m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread
                if (m_pWdfRequest != NULL)
                {
                    CompleteOneRemovalEvent();
                }
            }
            else
            {
                hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
            }
        }
        else
        {
            hr = E_INVALIDARG;
        }
        pWdfInputMemory->Release();
    }
    
    LeaveCriticalSection(&m_RoleLock);

    MethodReturnHR(hr);
}

HRESULT
CFileContext::SetPayload(_In_ IWDFIoRequest* pWdfRequest)
{
    MethodEntry("...");
    
    EnterCriticalSection(&m_RoleLock);
    
    HRESULT hr = S_OK;
    if ((m_Role != ROLE_PUBLICATION) || (m_MyPayload.GetPayload() != NULL))
    {
        // SetPayload can only be called once per handle
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }
    
    if (SUCCEEDED(hr))
    {
        IWDFMemory* pWdfOutputMemory;
        pWdfRequest->GetOutputMemory(&pWdfOutputMemory); 
        SIZE_T cbOutput;
        if (pWdfOutputMemory->GetDataBuffer(&cbOutput) == NULL)
        {
            IWDFMemory* pWdfMemory;
            pWdfRequest->GetInputMemory(&pWdfMemory);
            if (pWdfMemory != NULL)
            {
                SIZE_T cbPayload = pWdfMemory->GetSize();
                if ((cbPayload > 0) && (cbPayload <= MaxCbPayload))
                {
                    hr = m_MyPayload.Initialize((DWORD)cbPayload, (PBYTE)pWdfMemory->GetDataBuffer(NULL));
                }
                else
                {
                    hr = HRESULT_FROM_NT(STATUS_INVALID_BUFFER_SIZE);
                }

                pWdfMemory->Release();
            }
            else
            {
                hr = E_INVALIDARG;
            }
            pWdfOutputMemory->Release();
        }
        else
        {
            hr = E_INVALIDARG;
        }
    }

    LeaveCriticalSection(&m_RoleLock);

    MethodReturnHR(hr);
}

HRESULT
CFileContext::GetNextTransmittedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest)
{
    MethodEntry("...");
    
    EnterCriticalSection(&m_RoleLock);
    
    HRESULT hr = S_OK;
    if ((m_Role != ROLE_PUBLICATION) || (m_pWdfRequest != NULL))
    {
        // Only one pended request at a time allowed
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }
    
    if (!m_fEnabled)
    {
        // The handle is disabled
        hr = HRESULT_FROM_NT(HRESULT_FROM_NT(STATUS_CANCELLED));
    }
    
    if (SUCCEEDED(hr))
    {
        IWDFMemory* pWdfInputMemory;
        pWdfRequest->GetInputMemory(&pWdfInputMemory);
        SIZE_T cbInput;
        if (pWdfInputMemory->GetDataBuffer(&cbInput) == NULL)
        {
            IWDFMemory* pWdfOutputMemory;
            pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
            SIZE_T cbOutput;
            if (pWdfOutputMemory->GetDataBuffer(&cbOutput) == NULL)
            {
                m_pWdfRequest = pWdfRequest;

                if (m_cCompleteReady > 0)
                {
                    if (CompleteRequest(S_OK, 0, false))
                    {
                        m_cCompleteReady--;
                    }
                }
            }
            else
            {
                hr = E_INVALIDARG;
            }
            pWdfOutputMemory->Release();
        }
        else
        {
            hr = E_INVALIDARG;
        }
        pWdfInputMemory->Release();
    }

    if (SUCCEEDED(hr) && (m_pWdfRequest != NULL))
    {
        m_pWdfRequest->MarkCancelable(pCallbackCancel);
    }
    
    LeaveCriticalSection(&m_RoleLock);

    MethodReturnHR(hr);
}

HRESULT
CFileContext::BeginProximity(
    _In_ IWDFIoRequest*       pWdfRequest,
    _In_ IConnectionCallback* pCallback
    )
{
    MethodEntry("...");
    
    EnterCriticalSection(&m_RoleLock);
    
    HRESULT hr = S_OK;
    if (m_Role != ROLE_UNDEFINED)
    {
        // BeginProximity can only be called once per handle
        hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
    }
    else
    {
        m_Role = ROLE_PROXIMITY;
    }

    LeaveCriticalSection(&m_RoleLock);

    if (SUCCEEDED(hr))
    {
        IWDFMemory* pWdfMemory;
        pWdfRequest->GetInputMemory(&pWdfMemory);
        if (pWdfMemory != NULL)
        {
            if (pWdfMemory->GetSize() == sizeof(BEGIN_PROXIMITY_ARGS))
            {
                hr = CConnection::Create(pCallback, &m_pConnection);
                if (SUCCEEDED(hr))
                {
                    BEGIN_PROXIMITY_ARGS* pArgs = 
                        (BEGIN_PROXIMITY_ARGS*)pWdfMemory->GetDataBuffer(NULL);
                    hr = m_pConnection->InitializeAsClient(pArgs);
                }
            }
            else
            {
                hr = E_INVALIDARG;
            }
            
            pWdfMemory->Release();
        }
        else
        {
            hr = E_INVALIDARG;
        }
    }

    
    if (FAILED(hr))
    {
        m_pConnection = NULL;
    }
    
    MethodReturnHR(hr);
}

VOID
CFileContext::HandleArrivalEvent()
{
    WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_ARRIVEDSUBSCRIPTION);

    EnterCriticalSection(&m_RoleLock);
    
    if (m_fEnabled)
    {
        m_cCompleteReady++;
        CompleteOneArrivalEvent();
    }
    
    LeaveCriticalSection(&m_RoleLock);
}

VOID
CFileContext::HandleRemovalEvent()
{
    WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_DEPARTEDSUBSCRIPTION);
    
    EnterCriticalSection(&m_RoleLock);

    if (m_fEnabled)
    {
        m_cCompleteReady++;
        CompleteOneRemovalEvent();
    }
    
    LeaveCriticalSection(&m_RoleLock);
}

VOID
CFileContext::CompleteOneArrivalEvent()
{
    MethodEntry("void");
    
    WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_ARRIVEDSUBSCRIPTION);
    
    EnterCriticalSection(&m_RoleLock);

    if (m_cCompleteReady > 0)
    {
        if (m_pWdfRequest != NULL)
        {
            // Arrival payload should either be a DWORD = 1 or 0
            // 1 == Device capable of bi-directional communication
            // 0 == Device is a dumb tag
            DWORD ArrivalFlags = 0x1;
            if (CompleteOneGetNextSubscribedMessage(sizeof(ArrivalFlags), (PBYTE)&ArrivalFlags))
            {
                m_cCompleteReady--;
            }
        }
    }
    
    LeaveCriticalSection(&m_RoleLock);

    MethodReturnVoid();
}

VOID
CFileContext::CompleteOneRemovalEvent()
{
    MethodEntry("void");
    
    WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_DEPARTEDSUBSCRIPTION);
    
    EnterCriticalSection(&m_RoleLock);

    if (m_cCompleteReady > 0)
    {
        if (m_pWdfRequest != NULL)
        {
            // Removal payload should be a single zeroed DWORD
            DWORD RemovalFlags = 0x0;
            if (CompleteOneGetNextSubscribedMessage(sizeof(RemovalFlags), (PBYTE)&RemovalFlags))
            {
                m_cCompleteReady--;
            }
        }
    }
    
    LeaveCriticalSection(&m_RoleLock);

    MethodReturnVoid();
}

void
CFileContext::HandleReceivedPublication(
    _In_                   PCWSTR pszType,
    _In_                   DWORD  cbPayload, 
    _In_reads_bytes_(cbPayload) PBYTE  pbPayload
    )
{
    MethodEntry("...");
    
    WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_SUBSCRIPTION);
    
    EnterCriticalSection(&m_RoleLock);

    if (m_fEnabled)
    {
        bool fSubscriptionMatches = false;
        BYTE* pbNewPayload = NULL;

        if ((CompareStringOrdinal(m_pszType, -1, WINDOWSMIME_PROTOCOL, -1, FALSE) == CSTR_EQUAL) &&
            (wcslen(pszType) > WINDOWSMIME_PROTOCOL_CHARS) &&
            (CompareStringOrdinal(pszType, WINDOWSMIME_PROTOCOL_CHARS,
                                  WINDOWSMIME_PROTOCOL, -1, FALSE) == CSTR_EQUAL))
        {
            // If this is a WindowsMime message, and the subscription is for the general WINDOWSMIME_PROTOCOL type,
            // the Mime type needs to be added to the message payload.
            CHAR szMimeType[MaxCchMimeType + 1] = {};
            // Copy the mime type and convert from wide to multibyte chars
            if (SUCCEEDED(StringCchPrintfA(szMimeType, ARRAYSIZE(szMimeType), "%S", pszType + WINDOWSMIME_PROTOCOL_CHARS + 1)))
            {
                pbNewPayload = new BYTE[cbPayload + MaxCchMimeType];
                if (pbNewPayload != NULL)
                {
                    TraceInfo("Received Mime message of type = '%s'", szMimeType);
                    CopyMemory(pbNewPayload, szMimeType, MaxCchMimeType);
                    CopyMemory(pbNewPayload + MaxCchMimeType, pbPayload, cbPayload);
                    cbPayload += MaxCchMimeType;
                    pbPayload = pbNewPayload;

                    fSubscriptionMatches = true;
                }
            }
        }
        else if (CompareStringOrdinal(pszType, -1, m_pszType, -1, FALSE) == CSTR_EQUAL)
        {
            fSubscriptionMatches = true;
        }

        if (fSubscriptionMatches)
        {
            bool fDelivered = false;
            
            if (m_pWdfRequest != NULL)
            {
                fDelivered = CompleteOneGetNextSubscribedMessage(cbPayload, pbPayload);
            }

            if ((!fDelivered) && (m_dwQueueSize < MAX_MESSAGE_QUEUE_SIZE))
            {
                // Add message to the client delivery queue
                
                CMyPayload* pMyPayload = new CMyPayload();
                if (pMyPayload)
                {
                    if (SUCCEEDED(pMyPayload->Initialize(cbPayload, pbPayload)))
                    {
                        InsertTailList(&m_SubscribedMessageQueue, pMyPayload->GetListEntry());
                        m_dwQueueSize++;
                    }
                    else
                    {
                        delete pMyPayload;
                    }
                }
            }
        }

        delete [] pbNewPayload;
    }
    else
    {
        TraceErrorHR(HRESULT_FROM_NT(STATUS_CANCELLED), "Subscription Disabled!");
    }
    
    LeaveCriticalSection(&m_RoleLock);

    MethodReturnVoid();
}

void
CFileContext::HandleMessageTransmitted()
{
    MethodEntry("void");
    
    WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_PUBLICATION);
    
    EnterCriticalSection(&m_RoleLock);

    if (!CompleteRequest(S_OK, 0, true))
    {
        m_cCompleteReady++;
    }
    
    LeaveCriticalSection(&m_RoleLock);
    
    MethodReturnVoid();
}

void
CFileContext::OnCancel()
{
    EnterCriticalSection(&m_RoleLock);

    CompleteRequest(E_ABORT, 0, false);
    
    LeaveCriticalSection(&m_RoleLock);
}

bool
CFileContext::CompleteRequest(_In_ HRESULT hr, _In_ SIZE_T cbSize, _In_ bool fIsCancelable)
/*
 * m_RoleLock must already be acquired
 */
{
    MethodEntry("hr = %!HRESULT!, cbSize = %d, fIsCancelable = %!bool!",
                 hr,       (DWORD)cbSize,      fIsCancelable);
    
    bool fCompleted = false;
    if (m_pWdfRequest != NULL)
    {
        bool fCompleteRequest = true;
        if (fIsCancelable)
        {
            if (m_pWdfRequest->UnmarkCancelable() == HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED))
            {
                fCompleteRequest = false;
            }
        }

        if (fCompleteRequest)
        {
            m_pWdfRequest->CompleteWithInformation(hr, cbSize);
            m_pWdfRequest = NULL;
            fCompleted = true;
        }
    }

    MethodReturnBool(fCompleted);
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS