laser36
驱动牛犊
驱动牛犊
  • 注册日期2001-09-11
  • 最后登录2005-01-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:8346回复:27

如何判断过滤、分层驱动程序收到的IRP是否是发给自己的?

楼主#
更多 发布于:2002-03-29 09:33
设有“设备驱动程序A - 过滤、分层驱动程序B - 过滤、分层驱动程序C ”分层形式。A、B、C 都要分别和 WIN32 应用程序交换数据。当然,A、B、C 都暴露了设备名。

毫无疑问,A 和 B 的IRP都被 C 接收了,那么,当“过滤、分层驱动程序B”收到一个IRP,比如是IRP_MJ_READ,如何知道此IRP是发给自己的还是发给“设备驱动程序A ”的?


[编辑 -  4/1/02 作者: laser36]

最新喜欢:

chxunchxun root60931root60... nicolnicol flyfoxflyfox znsoftznsoft
pengyc
驱动牛犊
驱动牛犊
  • 注册日期2001-07-16
  • 最后登录2010-04-11
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-04-04 08:44
B,C要与win32通信,所以要创建两个设备对象. 如果一个驱动程序创建了多个设备对象,  为了区分它们, 可以在创建时在设备对象扩展中设置标志.FiDO是\"影子\"对象, 不应该暴露给用户, 所以不需要设备名和符号连接.

这是我看了上面诸位的讨论后的理解,不知对否?
liumeng
驱动牛犊
驱动牛犊
  • 注册日期2002-04-03
  • 最后登录2005-03-12
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-04-03 19:57
实在是太精彩了,可惜咱没有做过过滤驱动程序,不过小弟确实想学习一下,请各位大侠指点一下,应该看些什么资料?谢谢!!!!!!! :)



[编辑 -  4/3/02 作者: liumeng]
laser36
驱动牛犊
驱动牛犊
  • 注册日期2001-09-11
  • 最后登录2005-01-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-04-03 10:04
怎么俺一分都没有啊??? :( :( :( :(


guardee,你好:

并非我吝啬分,而是你的回答不够建设性,如果你能够给出“给过滤设备命名并且提供符号连接的驱动程序”的实现代码部分,我当然会给高分。你不会太保守吧。
 :) :) :) :)
Tom_lyd
驱动大牛
驱动大牛
  • 注册日期2001-09-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-04-02 11:13
谢谢laser36给分,我的邮箱今天不能用,不知163.net今天又搞什么鬼,我再上传一份吧。
Tom_lyd
Iamme
驱动小牛
驱动小牛
  • 注册日期2001-03-23
  • 最后登录2005-10-11
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-04-02 09:43
to guardee :

是,照你的说法是这样的
不过我并没有说B、C要创建两个设备对象啊
我看看
可能是我把主题就理解错了?
Go,go ahead
guardee
驱动巨牛
驱动巨牛
  • 注册日期2002-11-08
  • 最后登录2010-05-29
  • 粉丝2
  • 关注1
  • 积分2分
  • 威望34点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-04-01 21:48
怎么俺一分都没有啊??? :( :( :( :(
guardee
驱动巨牛
驱动巨牛
  • 注册日期2002-11-08
  • 最后登录2010-05-29
  • 粉丝2
  • 关注1
  • 积分2分
  • 威望34点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-04-01 21:47
To:Iamme
你的看法有误,
发向B的IRP不一定经过C
你编两个驱动程序试一下吧!因为对于A、B、C
A有一个目标设备对象A,B创建了两个设备对象B1和B2其中B1是钩挂在A之上的过滤设备对象,C也创建了两个设备对象C1和C2,C1是钩挂在B1之上的过滤设备对象,而B2及C2是驱动程序为了响应WIN32应用程序的消息的设备对象,那么对于发送给B2的请求,,驱动程序C是拦截不到的
laser36
驱动牛犊
驱动牛犊
  • 注册日期2001-09-11
  • 最后登录2005-01-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-04-01 20:10
Tom_lyd:

当你看到此贴时,我的分已给了,它表示感谢和对助人行为的奖赏,而且你们的贴子也启发了我。但并不表示我就同意你的帖子。

我下载了FILEMON 文件,我并未通读,但快速地查看了它的扩展变量标记,我在头文件中找到了记录:
typedef struct {
    FILE_SYSTEM_TYPE Type;
    PDEVICE_OBJECT   FileSystem;
    unsigned         LogicalDrive;
    BOOLEAN          Hooked;
    PFILE_FS_ATTRIBUTE_INFORMATION FsAttributes;
} HOOK_EXTENSION, *PHOOK_EXTENSION;        
这应该就是标记了,如果它们之一能标记 IRP 之目的地,那么它就不能是某判断之结果,可是我找到了如下一类的内容:
HookSpecialFs(
    IN PDRIVER_OBJECT DriverObject,
    FILE_SYSTEM_TYPE FsType
)

PHOOK_EXTENSION     hookExtension;

    hookExtension = hookDevice->DeviceExtension;
    hookExtension->LogicalDrive = \'\\\\\';
    hookExtension->FileSystem   = topAttachDevice;
    hookExtension->Hooked       = TRUE;
hookExtension->Type = FsType;

        hookExtension = hookDevice->DeviceExtension;
        hookExtension->LogicalDrive = \'A\'+Drive;
        hookExtension->FileSystem   = fileSysDevice;
        hookExtension->Hooked       = TRUE;
        hookExtension->Type         = STANDARD;

UnhookSpecialFs(
    FILE_SYSTEM_TYPE FsType
    )
{
    PHOOK_EXTENSION   hookExt;

等等之类,可知,虽然扩展变量标记可作为判别条件,可惜同样是某些判别结果,根据在学校教育的经验可知,它的否定证明成立了--至少在此源码包中。除非你能给出更可靠的证据。

Iamme 问题也很有意思。

另外,2002-04-01_多重过滤.doc 附件无法下载,能否发到我的邮箱? (laser369@263.net)

再次表示感谢!!!
 :D

[编辑 -  4/1/02 作者: laser36]
Iamme
驱动小牛
驱动小牛
  • 注册日期2001-03-23
  • 最后登录2005-10-11
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-04-01 16:28
我不这样认为
B、C并不需要分别创建2个设备对象
发向A的IRP必然经过B、C,而发向B的IRP必然经过C
因为IO管理器发送IRP的目标是设备栈而不是设备
IO管理器只把IRP发到某个设备栈的顶端
向下传的动作是由设备驱动来做的
所以在设备栈的任何一层都可能并且可以完成该IRP并返回
Go,go ahead
Tom_lyd
驱动大牛
驱动大牛
  • 注册日期2001-09-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-04-01 14:45
To laser36:
    laser36:我仔细想了一下这些问题,发现我的回答存在一些不确切之处,特此更正,并表示道歉!
    其实你的问题的实质是反映了一个多层过滤的问题。在设备A的顶端存在着B、C两相过滤器,原本直接到A的请求会先后经过C和B。A、B、C都暴露了设备名是为了和Win32建立连接关系以和它进行通信,满足用户的一些设置要求。
    这里A是天经地义的,因为它不是过滤驱动程序,肯定有设备名。而B、C在这里也有设备名是因为它在创建了一个过滤设备对象以外,还创建了一个处理来自Win32用户设置的设备对象,这个设备对象不是过滤设备对象,当然它可以有设备名,并且它跟普通的目标设备对象的地位是平等的。
    设备对象栈构成以后,IRP的处理流程便形成以来。到A的IRP无一遗漏地会依次经过C和B,并处理这些IRP的必定是C和B建立的过滤设备对象,而是不那个有设备对象名的和Win32通信的设备对象。分开来说,B创建的过滤设备对象接受到的IRP必定是传到A的,而不可能是想传到自己的,而传到B创建的普通设备对象(有设备对象名)的IRP必定是来自Win32的用户设置,这个IRP不可能是发到A的;同样,如果C也是A的过滤设备对象,则所有到A的请求都会无一遗漏地经过C创建的过滤设备对象,而所有对C的有关设备IRP(来自Win32)都会经过C创建的普通设备对象(有设备名的)。说到这里也许我还并没有真正解决你的问题,那么请看下面:
     假如B、C都创建了两个设备对象,一个有名字,一个无名字。有名字的不是过滤器,它负责接收来自Win32的设置,无名字的负责过滤到目标驱动程序的IRP。则当B的用户端发送一个IRP到有名的设备对象时,它的IRP不会经过C,也不会下传到A。因为C是A的过滤,C在挂接到A时(我默认所有的过滤器都是上层过滤),并不是直接挂接到A的设备对象本身,而是通过一系列的调用得到A可能已有的上层过滤驱动。这里就是B。因此,C便将自己创建的设备对象(无名的)挂接在B创建的过滤设备对象上方。正因为这样,到A的请求才会依次经过C和B。但是,C不是B的过滤(严格地说C不是B创建的有名的设备对象的过滤,所以从B的客户程序传来的请求不会经过C,而是经由I/O Manager直接传给B。C在注册过滤设备对象时尽管连接到的目标设备对象是A的最上层过滤设备对象B,但是B创建了两个设备对象,它只是连接到了其中的一个。所以我估计,这一点就是laser36兄弟最大的疑惑。
    我特用一个图形表示这个流程,见附近!
  
    另外,我的错误在于在DeviceExtension中作标记标志IRP的去向,这是错误的, 在此我特地更正,也向laser36及各位兄弟道歉。
    我之所以认为这样是因为看到File monitor的源代码,后经仔细分析后,FM设置此项的理由是它创建的多个设备对象共享Dispatch例程和Fast I/O 例程,然后在Dispatch和Fast I/O 例程中根据设备扩展中的此项来判断接受到的IRP是到哪个设备对象的。这只是一个处理技巧,不管怎么说还是值得借鉴。
    
    




 
Tom_lyd
Iamme
驱动小牛
驱动小牛
  • 注册日期2001-03-23
  • 最后登录2005-10-11
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-04-01 11:27
还有啊
你为什么要判断是否发给自己的呢?
其实把自己的应用可能发给自己的设备对象的指令都定义成Io Control Code,用DeviceIoControl传下去不可以吗?
这样也就不需要判断了,只要把感兴趣的东东截获就可以了
Go,go ahead
Iamme
驱动小牛
驱动小牛
  • 注册日期2001-03-23
  • 最后登录2005-10-11
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2002-04-01 11:15
1. 即使是普通的命名的设备对象,哪怕连DosDeviceName也有
也是可以通过IoAttachToDeviceStack连接到某个设备对象上的,
只要先通过设备名用IoGetDeviceObjectPointer获得要被连接
设备对象指针
2. 判断是否发给自己的能否通过IoGetCurrentProcess( )来获
得呢?
Go,go ahead
jansen
驱动小牛
驱动小牛
  • 注册日期2001-10-21
  • 最后登录2007-10-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2002-04-01 08:25
精彩,这样的讨论多多益善!
rich
Tom_lyd
驱动大牛
驱动大牛
  • 注册日期2001-09-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2002-03-31 21:05
Laser36兄弟:
    对于你的如下解答:
    1.我在附件里附了两副图,是讲解Filter的原理的,有助于理解设备对象的用途。
    2.你需要的File monitor的源码在www.systeminternals.com网站有下,是Free的。
    3.Win2000驱动程序是包驱动的,包即IRP。IRP是由I/O Manager系统组件构造的,它构造IRP并不是凭空的,而是依赖于应用程序或内部其它驱动程序传递来的请求参数。打个比方来方应用程序app.exe需要调用NTFS.sys提供的文件服务进行文件操作,它发出请求到I/O Manager,I/O Manager接到请求以后它能立即分析出这些内容:\"app.exe某人请求我去跟NTFS.sys大人打个报告,叫他老大人高抬贵手让我进行一些文件操作\"。NTFS.sys自身当然是死的,但是他的替身NTFS文件系统的设备对象(只有Win2000运行时才被创建)接管所有的这些东西。这里我所需要注意的是I/O Manager组件一定能根据app.exe传来的参数判断出app.exe需要的是NTFS.sys(严格地说是它创建的设备对象)提供的服务,而不是FAT32.sys(严格地说是FAT32创建的设备对象)。所以这是第一点,应用程序的具体要求它自己会说清楚,不会麻烦I/O Manager老大人,否则 的话I/O Manager一定会气得翘起胡子骂道:\"连自己要干什么都不知道就跑到我这来瞎胡闹,去去去\"。第二点,我们再回到你创建的设备对象上来。
    你至少需要创建不少于两个设备对象,一个用来供用户设备信息,这个设备对象的WHERE==ToMyself,只有那些你的设备请求会被传递到这里来,到目标驱动程序的IRP一定不会光顾它。此外,你还需要创建一个Filteror(过滤设备对象),是用来截获到目标程序的IRP的,这个WHERE==ToTargetDevice,任何本想发到目标驱动程序的IRP都会光顾这里,可别忘记了,你在创建这个DeviceObject成功后,一定有IoAttachDeviceToDeviceStack(PSOURCEDEVICE,PTARGETDEVICE)或类似的调用,只有这样,你才能过滤人家呀!并且,只有原本想到PTARGETDEVICE的IRP请求才会到(一定会到)你创建的Filteror里,其它的一般来说不会过来。至少I/O Manager没有那么糊涂。
    设备对象一经创建后,里面的内容是相对固定的,而IRP却是活的,它就象Windows2000的循环系统,流淌着鲜活的血液,维系着Windows2000的运行。IRP被发送到谁不是由它自己决定的,它的命运被牢牢着掌握在I/O Manager系统组件手里,至于I/O Manager要将IRP的命运转交给谁去驾驭,就看是谁要求I/O Manager去构建这个IRP。
    我不知道我这样说你能否理解清楚。如果还不能理解清楚,请仔细阅读File monitor的源码。

best regards !

附件名称/大小 下载次数 最后更新
2002-03-31_Filter.doc (52KB)  8
Tom_lyd
Tom_lyd
驱动大牛
驱动大牛
  • 注册日期2001-09-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2002-03-31 20:37
Tom_lyd
laser36
驱动牛犊
驱动牛犊
  • 注册日期2001-09-11
  • 最后登录2005-01-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2002-03-31 16:38
Tom_lyd:

在设备扩展数据结构中加一个标志位enum WHERE whom变量,以及可以自己来填入信息我都没有异议,可是,就如同你所说的“里面的信息内容,不是系统填写的,是由你自己来填写的”,那么过滤程序收到IRP后,系统并不会自动修改whom变量,那么又如何根据此whom变量来判断IPP是发给谁的?而且,IRP本身应该也不携带有whom变量信息。所以,对于为什么能用enum WHERE whom变量来判断IRP地目的地,我实在还是有些胡涂,另外,你提到的File monitor的源码和IFSKIT 能否发给我,我好仔细研究研究。

邮箱: laser369@263.net ,(此信箱可收8M附件,可放12M数据)



[编辑 -  3/31/02 作者: laser36]

[编辑 -  4/1/02 作者: laser36]
guardee
驱动巨牛
驱动巨牛
  • 注册日期2002-11-08
  • 最后登录2010-05-29
  • 粉丝2
  • 关注1
  • 积分2分
  • 威望34点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2002-03-30 19:06
我就写过给过滤设备命名并且提供符号连接的驱动程序,可能这个微软不赞成这么做罢了!
Tom_lyd
驱动大牛
驱动大牛
  • 注册日期2001-09-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2002-03-30 17:01
< BACK  NEXT >
[oR]

Writing Filter Drivers
A filter driver is a special type of intermediate driver. Filter drivers perform their work surreptitiously. They sit on top of some other driver and intercept requests directed at the lower driver\'s Device objects. Users of the lower driver are completely unaware that their requests are being preprocessed or intercepted by the filter driver. Some examples of the use of filter drivers include the following:

Filters allow modification of some aspect of an existing driver\'s behavior without rewriting the entire driver. SCSI filter drivers work this way.

Filters make it easier to hide the limitations of lower-level device drivers. For example, a filter could split large transfers into smaller pieces before passing them on to a driver with transfer size limits.

Filters allow the addition of new features like compression or encryption to a device without modifying the underlying device driver or the programs that use the device.

Filters allow the addition or removal of expensive behavior (like performance monitoring) a driver may not perform at all times. The disk performance monitoring tools in Windows 2000 work this way.

The remainder of this section explains how to write filter drivers. Bear in mind that driver-allocated IRPs and I/O Completion routines work the same in a filter driver as they do in a regular layered driver.

How Filter Drivers Work
The main distinction between filter drivers and other layered drivers is in the Device objects they create. Whereas a layered driver exposes Device objects with their own unique names, filter drivers\' Device objects have no names at all. Filter drivers work by attaching one of these nameless Device objects to a Device object created by some lower-level driver. Figure 15.2 illustrates this relationship.

Figure 15.2. Filter driver operation.
 
In the diagram, FLTDRIVER has attached a filter Device object to FD0, one of FDODRIVER\'s Device objects. Any IRPs sent to FD0 are automatically rerouted to the Dispatch routines in FLTDRIVER. It works as follows:

The AddDevice routine in the filter driver creates an invisible Device object and attaches it to a named Device object belonging to a driver beneath it.

A client of the lower-level driver opens a connection to FD0. This is typically done using the Win32 CreateFile method to obtain a handle, or a kernel-mode client can use IoGetDeviceObjectPointer. Regardless, the I/O Manager actually opens a connection between the client and the filter driver\'s invisible Device object.

When the client sends an I/O request to FD0, the I/O Manager sends it to the filter driver\'s unnamed Device object instead. The I/O Manager uses the MajorFunction table of the filter\'s Driver object to select an appropriate Dispatch routine.

The Dispatch routines in the filter driver either process the IRP on their own and complete immediately, or they send the IRP down to FD0 with IoCallDriver. If the filter driver needs to regain control of the IRP when a lower-level driver completes it, the filter can associate an I/O Completion routine with the IRP.

Filters can also be layered above other filters. Attaching a new filter to an already filtered Device object results in the new filter simply getting layered on top of the highest existing filter. Essentially, any number of filter layers can exist for a single Device object.

Initialization and Cleanup in Filter Drivers
Like every other kernel-mode driver, a filter driver must have a main entry point called DriverEntry. Like other WDM drivers, it must export an AddDevice, RemoveDevice, and Unload routine. The following sections describe what these routines must do.

AddDevice routine
The initialization sequence in a filter driver for the PnP request to add a device is straightforward.

The filter calls IoCreateDevice to create a filter Device object for this target device. The filter Device object has no internal name, nor does it have a symbolic link name.

It calls IoAttachDeviceToDeviceStack (as usual) to stack itself on top of the lower driver and obtain a pointer to the target Device object.

It stores the address of the target device object in the Device Extension of the filter Device object. Other parts of the filter driver use this pointer to call the target driver.

Next, AddDevice copies the DeviceType and Characteristics fields from the target Device object to the filter Device object. It also copies the DO_DIRECT_IO, DO_BUFFERED_IO, DO_POWER_INRUSH, and DO_POWER_PAGABLE bits from the target Device object\'s Flags field. This guarantees that the filter looks the same and has the same buffering strategy as the target driver.

RemoveDevice Routine
A filter driver\'s RemoveDevice routine must disconnect the filter and target Device objects. It does this by calling IoDetachDevice and passing a pointer to the target Device object. Once the filter Device object has been detached, the RemoveDevice routine calls IoDeleteDevice to delete the unnamed object.

Making the Attachment Transparent
Once a filter has attached itself to the target driver, any I/O requests sent to the target must pass through the Dispatch routines of the filter driver first. If the MajorFunction table of the filter Driver object does not support the same set of IRP_MJ_XXX codes as the target driver, clients of the target may experience problems when the filter is attached. Specifically, some types of requests that work without the filter are rejected as illegal operations when the filter is in place.

To avoid this inconsistency, the filter driver\'s MajorFunction table must contain a Dispatch routine for every IRP_MJ_XXX function supported by the target driver. Even if the filter is not interested in modifying a particular MajorFunction code, it still must supply the Dispatch routine that simply passes the IRP on to the target driver.

The most straightforward way for the filter driver to avoid the inconsistency problem is to provide a pass-through Dispatch routine for every slot within the MajorFunction table of the filter Driver object. For each MajorFunction entry that the filter wishes to override, a non-pass-through function is provided. The sample driver in the next section demonstrates this technique.

< BACK  NEXT >
 guardee兄弟:
    你可以保留你的观点,或许你的观点是对的,因为毕竟WDM不是我们创造的,概念也不是我们创造的。我之所以说过滤设备对象是无设备对象名和符号连接名是有证据的。
    以上的文章是从Art Baker、 Jerry Lozano著的《Windows 20000设备驱动程序设计指南》中第15章\"分层驱动程序的设计\"摘出来的一段。
    另外,不知你有没有看DDK文档中关于IoCreateDevice函数中关于DeviceName参数的说明,如下:
DeviceName
Optionally points to a buffer containing a zero-terminated Unicode string that names the device object. The string must be a full path name.
Typically, only Physical Device Objects (PDOs), which are created by PnP bus drivers, are named. PnP function drivers and filter drivers should not specify a DeviceName for a Functional Device Object (FDO) or filter device object (filter DO). Naming an FDO or filter DO bypasses the PnP Manager\'s security. If a user-mode component needs a symbolic link to the device, the function or filter driver should register a device interface (see IoRegisterDeviceInterface ). If a kernel-mode component needs a legacy device name, the driver must name the FDO, but naming is not recommended.
Tom_lyd
guardee
驱动巨牛
驱动巨牛
  • 注册日期2002-11-08
  • 最后登录2010-05-29
  • 粉丝2
  • 关注1
  • 积分2分
  • 威望34点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2002-03-30 16:34
不对
过滤设备对象也可以有设备对象名和符号连接
上一页
游客

返回顶部