命名管道与Mailslot

原文地址:http://book.51cto.com/art/200912/174785.htm

在做驱动与应用层使用命名管道通讯时,不知道如何在驱动中打开命名管道的路径,原来驱动中的路径名为:"\Device\NamedPipe\MyPipe",应去层用的是"\\\\.\\Pipe\\MyPipe"

再看IoCreateFile()怎样找到命名管道驱动模块的设备对象。创建了一个命名管道以后,在对象目录中就有了一个相应的节点,例如"\Device\NamedPipe\MyPipe"。注意这里的节点"NamedPipe"是个设备对象,而设备对象提供解析函数。这样,对象管理的ObOpenObjectByName()就能根据全路径找到其具体命名管道所属的"目录""\Device\NamedPipe"(如果目标尚未创建)或代表着这个目标的对象。这二者都会有指针指向命名管道驱动模块的设备对象(如果已经装载)。下面就是驱动模块的事了。

我们看命名管道驱动模块的初始化:

 
 
  1. NTSTATUS STDCALL    //ReactOS-0.3.3\drivers\filesystems\npfs\npfs.c  
  2. DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)  
  3. {  
  4.    PNPFS_DEVICE_EXTENSION DeviceExtension;  
  5.    ......  
  6.  
  7.    DPRINT("Named Pipe FSD 0.0.2\n");  
  8.    ASSERT (sizeof(NPFS_CONTEXT) <= FIELD_OFFSET(IRP, Tail.Overlay.DriverContext));  
  9.    ASSERT (sizeof(NPFS_WAITER_ENTRY) <=  
  10.                                     FIELD_OFFSET(IRP,  Tail.Overlay.DriverContext));  
  11.  
  12.    DriverObject->MajorFunction[IRP_MJ_CREATE]   = NpfsCreate;  
  13.    DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] =  
  14.                                                 NpfsCreateNamedPipe;  
  15.    DriverObject->MajorFunction[IRP_MJ_CLOSE]        = NpfsClose;  
  16.    DriverObject->MajorFunction[IRP_MJ_READ]         = NpfsRead;  
  17.    DriverObject->MajorFunction[IRP_MJ_WRITE]        = NpfsWrite;  
  18.    DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =  
  19.                                                 NpfsQueryInformation;  
  20.    DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =  
  21.                                                 NpfsSetInformation;  
  22.    DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =  
  23.                                                  NpfsQueryVolumeInformation;  
  24.    DriverObject->MajorFunction[IRP_MJ_CLEANUP]  = NpfsCleanup;  
  25.    DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = NpfsFlushBuffers;  
  26.    DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =  
  27.                                                 NpfsFileSystemControl;  
  28.    DriverObject->DriverUnload = NULL;  
  29.    RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");  
  30.    //在对象目录中创建一个名为"\Device\NamedPipe"的设备对象  
  31.    Status = IoCreateDevice(DriverObject, sizeof(NPFS_DEVICE_EXTENSION),  
  32.             &DeviceName, FILE_DEVICE_NAMED_PIPE, 0, FALSE, &DeviceObject);  
  33.    if (!NT_SUCCESS(Status)) return Status;    //创建设备对象失败  
  34.  
  35.    /* initialize the device object */  
  36.    DeviceObject->Flags = DO_DIRECT_IO;  
  37.    /* initialize the device extension */  
  38.    DeviceExtension = DeviceObject->DeviceExtension;  
  39.    InitializeListHead(&DeviceExtension->PipeListHead);   //所有命名管道FCB的队列  
  40.    InitializeListHead(&DeviceExtension->ThreadListHead);  
  41.    KeInitializeMutex(&DeviceExtension->PipeListLock, 0);  
  42.    DeviceExtension->EmptyWaiterCount = 0;  
  43.    /* set the size quotas */  
  44.    DeviceExtension->MinQuota = PAGE_SIZE;  
  45.    DeviceExtension->DefaultQuota = 8 * PAGE_SIZE;  
  46.    DeviceExtension->MaxQuota = 64 * PAGE_SIZE;  
  47.    return STATUS_SUCCESS;  

注意这里一方面使主功能为IRP_MJ_CREATE的函数指针指向NpfsCreate(),另一方面又使主功能为IRP_MJ_CREATE_NAMED_PIPE的函数指针指向NpfsCreateNamedPipe(),命名管道驱动是唯一提供后面这个主功能函数的驱动对象。

此外,这里并没有提供AddDevice函数,这说明命名管道的驱动是个"老式(Legacy)"的单块设备驱动,其设备对象不会被堆叠到别的设备对象上面。

由于路径名为"\Device\NamedPipe",IoCreateDevice()就在对象目录中的节点"\Device"下面创建了一个名为"NamedPipe"的设备对象,并使其指向所创建的命名管道设备对象。注意这里的FILE_DEVICE_NAMED_PIPE是设备类型,就像FILE_DEVICE_BEEP一样,而所创建对象的类型则是IoDeviceObjectType即设备对象。另一方面,设备对象是提供解析函数的。

设备对象的扩充部有个队列PipeListHead,队列中是所有已创建的命名管道。每个命名管道都有个"文件控制块"即NPFS_FCB数据结构,这个数据结构就挂在PipeListHead这个队列里面,这个队列就好像一个单层的目录。此外,从本质上说命名管道无非就是数据的"中转站",所以需要一定的缓冲区空间,这里还为此设置了配额。

创建了设备对象之后,内核的设备驱动框架就可以通过IRP和IoCallDriver()调用其主功能函数了。创建或打开命名管道时,就像对于别的设备一样,内核会为之创建一个代表着特定访问上下文的FILE_OBJECT,就是下面代码中的FileObject,并且系统调用所返回的句柄就代表着这个文件对象。

在设备对象的解析函数IopParseDevice()中,当文件类型为CreateFileTypeNamedPipe时所生成IRP的主功能码是IRP_MJ_CREATE_NAMED_PIPE,而在文件类型为CreateFileTypeNone时则是IRP_MJ_CREATE。也就是说,当IRP到达命名管道驱动模块的设备对象时,前者表示这是服务端的创建命名管道,而后者表示这是客户端的打开命名管道。

再看具体的主功能函数,其中最重要的是NpfsCreateNamedPipe()和NpfsCreate()。先看前者,NpfsCreateNamedPipe()是个比较大的函数,需要分段阅读。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值