(转)驱动开发之五 --- TDI之六 【译文】

http://hi.baidu.com/combojiang/item/d0287ca509180ddf5bf19132

同样的使用TDI_RECEIVE来完成数据接收。然而我们却没有用它来实现。实际上,如果你注意到,你可以创建回调来通知你数据或者其他事件什么时候到达。这就是我们所做的。我实现了一个API包装函数来创建任意的事件句柄。如下:

 

NTSTATUS TdiFuncs_SetEventHandler(PFILE_OBJECT pfoTdiFileObject,

            LONG InEventType, PVOID InEventHandler, PVOID InEventContext)

{

    NTSTATUS NtStatus = STATUS_INSUFFICIENT_RESOURCES;

    PIRP pIrp;

    IO_STATUS_BLOCK IoStatusBlock = {0};

    PDEVICE_OBJECT pTdiDevice;

    LARGE_INTEGER TimeOut = {0};

    UINT NumberOfSeconds = 60*3;

    TDI_COMPLETION_CONTEXT TdiCompletionContext;

 

    KeInitializeEvent(&TdiCompletionContext.kCompleteEvent,

                               NotificationEvent, FALSE);

 

    /*

     * The TDI Device Object is required to send these

     *                       requests to the TDI Driver.

     */

 

    pTdiDevice = IoGetRelatedDeviceObject(pfoTdiFileObject);

    

    /*

     * Step 1: Build the IRP. TDI defines several macros and functions

     *         that can quickly create IRP's, etc. for variuos purposes.  

     *         While this can be done manually it's easiest to use the macros.

     *

     */

    pIrp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER,

            pTdiDevice, pfoConnection, &TdiCompletionContext.kCompleteEvent,

            &IoStatusBlock);

 

    if(pIrp)

    {

        /*

         * Step 2: Set the IRP Parameters

         */

 

        TdiBuildSetEventHandler(pIrp, pTdiDevice, pfoTdiFileObject,

                NULL, NULL, InEventType, InEventHandler, InEventContext);

 

        NtStatus = IoCallDriver(pTdiDevice, pIrp);

 

       /*

         * If the status returned is STATUS_PENDING this means that

         * the IRP will not be completed synchronously and the driver has

         * queued the IRP for later processing. This is fine but we do not

         * want to return this thread, we are a synchronous call so we want

         * to wait until it has completed. The EVENT that we provided

         * will be set when the IRP completes.

         */

 

        if(NtStatus == STATUS_PENDING)

        {

            KeWaitForSingleObject(&TdiCompletionContext.kCompleteEvent,

                                    Executive, KernelMode, FALSE, NULL);

 

            /*

             * Find the Status of the completed IRP

             */

    

            NtStatus = IoStatusBlock.Status;

        }

 

    }

 

    return NtStatus;

}

 

使用这个函数实现回调的代码如下:

Collapse

NtStatus = TdiFuncs_SetEventHandler(

                  pTdiExampleContext->TdiHandle.pfoTransport,

                  TDI_EVENT_RECEIVE,

                  TdiExample_ClientEventReceive,

                  (PVOID)pTdiExampleContext);

  

...

 

NTSTATUS TdiExample_ClientEventReceive(PVOID TdiEventContext,

                         CONNECTION_CONTEXT ConnectionContext,

                         ULONG ReceiveFlags,

                         ULONG BytesIndicated,

                         ULONG BytesAvailable,

                         ULONG *BytesTaken,

                         PVOID Tsdu,

                         PIRP *IoRequestPacket)

{

    NTSTATUS NtStatus = STATUS_SUCCESS;

    UINT uiDataRead = 0;

    PTDI_EXAMPLE_CONTEXT pTdiExampleContext =

                        (PTDI_EXAMPLE_CONTEXT)TdiEventContext;

    PIRP pIrp;

 

    DbgPrint("TdiExample_ClientEventReceive 0x%0x, %i, %i\n",

                  ReceiveFlags, BytesIndicated, BytesAvailable);

 

 

    *BytesTaken = BytesAvailable;

    

    /*

     * This implementation is extremely simple. We do not queue

     * data if we do not have an IRP to put it there. We also

    * assume we always get the full data packet sent every recieve.

     * These are Bells and Whistles that can easily be added to

     * any implementation but would help to make the implementation

     * more complex and harder to follow the underlying idea. Since

     * those essentially are common-sense add ons they are ignored and

     * the general implementation of how to Queue IRP's and

     * recieve data are implemented.

     *

     */

 

    pIrp = HandleIrp_RemoveNextIrp(pTdiExampleContext->pReadIrpListHead);

 

    if(pIrp)

    {

        PIO_STACK_LOCATION pIoStackLocation =

                              IoGetCurrentIrpStackLocation(pIrp);

 

        uiDataRead =

               BytesAvailable > pIoStackLocation->Parameters.Read.Length ?

               pIoStackLocation->Parameters.Read.Length : BytesAvailable;

 

        pIrp->Tail.Overlay.DriverContext[0] = NULL;

 

        RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, Tsdu, uiDataRead);

 

        pIrp->IoStatus.Status      = NtStatus;

        pIrp->IoStatus.Information = uiDataRead;

 

        IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);

    }

 

    /*

     * The I/O Request can be used to recieve the rest of the data.  

     * We are not using it in this example however and will actually

     * be assuming that we always get all the data.

     *

     */

    *IoRequestPacket = NULL;

 

    return NtStatus;

}

不要对HandleIrp_RemoveNextIrp产生恐惧,我们会在本篇后面部分讲怎样排队IRP请求。

posted @ 2013-01-15 11:09  himessage  阅读(686)  评论(0编辑  收藏  举报