So I thought I'd give you all an end to end sample of how to forward requests to a lower driver w/ UMDF, or at least how I have it set up for the 1394 virtual device driver sample.  Your usage may vary and so may your mileage.

First off, UMDF uses file handles for associations, so we need to create one.  What I'm doing is storing the IWDFDriverCreatedFile object in my device class;

 

class VdevDevice : 
    public CUnknown,
    public IRequestCallbackRequestCompletion,
    public IPnpCallbackHardware
{
    //
    // This is our file object to the KMDF File
    // we'll need this to create and submit IOCTLs down to the kmdf stub
    // the life of the object will follow the life of the driver.
    //
    IWDFDriverCreatedFile * m_KmdfTargetFile;       
    
    //
    // We'll need these later
    //    
    IPnpCallbackHardware * 
    HardwareCallback (
                        VOID)
    {
        AddRef();
        return static_cast <IPnpCallbackHardware *> (this);
    }     
    
    STDMETHOD_
        (HRESULT, OnReleaseHardware) (
                            __in IWDFDevice * wdfDevice);
};

I'll also carry a copy of that file handle in my callback queue class;

class VdevSequentialQueue : 
    public IQueueCallbackDeviceIoControl,
    public IRequestCallbackCancel
{

    // ...some other members and such...  
public:

    IWDFDevice * m_BaseDevObj;
    IWDFFile * m_FileHandle;
};

Next during our device configuration, I'll create the file object;

 

HRESULT
VdevDevice::Configure ( 
                       VOID)
{

    // ...some other stuff...
    m_FxDevice->CreateWdfFile (L"KMDF_VDEV_DRIVER\n", &m_KmdfTargetFile);

    //...initialize the callback queues and some other things here...

    m_SequentialQueue->m_FileHandle = m_KmdfTargetFile;
    m_SequentialQueue->m_BaseDevObj = m_FxDevice;

    // ...and yet more stuff...
}

You'll notice I'm also carrying a loose reference the device object above, you'll see why in this next block;

VOID
STDMETHODCALLTYPE
VdevSequentialQueue::OnDeviceIoControl(
                                       __in IWDFIoQueue *FxQueue,
                                       __in IWDFIoRequest *wdfRequest,
                                       __in ULONG ControlCode,
                                       __in SIZE_T InputBufferSizeInBytes,
                                       __in SIZE_T OutputBufferSizeInBytes)
{

    IWDFIoTarget * kmdfIoTarget = NULL;
    IWDFIoRequest * kmdfIoRequest = NULL;

    // ....code, code, code...

    switch (ControlCode)
    {
    case IOCTL_WE_WANT:
        {

            m_BaseDevObj->GetDefaultTarget (&kmdfIoTarget);

            hr = m_BaseDevObj->CreateRequest (
                                    NULL, // we'll deal with completion later
                                    NULL, // defaults the object to self
                                    &kmdfIoRequest);
            if (FAILED (hr))
            {
                wdfRequest->Complete (hr);
                return;
            }

            hr = kmdfIoTarget->FormatRequestForIoctl (
                                    kmdfIoRequest, 
                                    IoCode,
                                    m_FileHandle,
                                    InputMemory,
                                    InputOffset,
                                    OutputMemory,
                                    OutputOffset);

            if (FAILED (hr))
            {
                wdfRequest->Complete (hr);
                return;
            }

            hr = kmdfIoRequest->Send (
                                    kmdfIoTarget, 
                                    WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, 
                                    0);   

            wdfCompleteRequest (hr);

        }
        break;
    }

}

There are built in methods for getting the values of m_BaseDevObj and m_FileHandle, but I found for my usage in this particular case, it's best to just keep a loose reference to those objects in my queue class(es).  As you probably have gathered, this request is being sent on a sequential queue and we're not doing anything with completion callbacks.  I'm working on adding asynchronous support in the KMDF driver, because if you have the WDK, you'll notice all the requests sent from the current virtual device driver are done so synchronously.  Yes, even the async requests. ;)

Now for the clean up, we'll need to release file handle in a clean up routine and it's best to do it during the OnReleaseHardware or OnSelfManagedIoCleanup to protect against a possible condition where a lower filter driver would have the IoTarget in a delete state;

 

HRESULT
VdevDevice::OnReleaseHardware (
                               __in IWDFDevice * wdfDevice)
{
       
    // 
    // Close the handle to the file object we've been using for 
    // our requests to the KMDF stub
    //
    m_KmdfTargetFile->Close();

    return S_OK;
}
 
So there we have it.  All nice 'n neat, no?  As always your questions / comments are welcome.
 
Sorry about all the updates, I'm playing with some CSS overrides and a new blog editor.
*Currently Playing - Alice in Chains Angry Chair