阅读:2577回复:11
应用程序和驱动程序进行通信的问题(DeviceIoControl),但在NDIS中驱动入口DriverEntry中该如何Dispatch呢?
我刚学NDIS编程,近日看到版中的应用程序和驱动程序进行通信的问题可以用DeviceIoControl来解决,我有一点不太清除,我的想法是这样:驱动中要DeviceIoControl支持,那么在驱动DriverEntry入口处必须在Dispatch中指明具体实现函数指针,但在NDIS中驱动入口DriverEntry中该如何Dispatch呢?,我不知道这样理解对不对,希望各位大侠多多批评......
|
|
最新喜欢:txysp
|
沙发#
发布于:2003-07-25 17:43
喜喜` 我知道~~ 不过我好保守~~ 不告诉你~~
|
|
|
板凳#
发布于:2003-07-25 18:22
看看xp passthru,有实现方法。
|
|
|
地板#
发布于:2003-07-25 19:06
喜喜` 我知道~~ 不过我好保守~~ 不告诉你~~ ..................................... |
|
|
地下室#
发布于:2003-07-25 20:51
是不是这样:
DriverObject->MajorFunction[IRP_MJ_CREATE] = ROpen; DriverObject->MajorFunction[IRP_MJ_CLOSE] = RClose; DriverObject->MajorFunction[IRP_MJ_READ] = RRead; DriverObject->MajorFunction[IRP_MJ_WRITE] = RWrite; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = RCleanup; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RIoControl; |
|
5楼#
发布于:2003-07-25 22:22
应该是这样把:
在DriverEntry调用 NdisMInitializeWrapper ( &hNdisWrapper, arg1, arg2, NULL ); MiniportInitialize; 然后在MiniportInitialize时执行以下代码: ControlDeviceState = PS_DEVICE_STATE_CREATING; NdisReleaseSpinLock ( &GlobalLock ); for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) DispatchTable = PtDispatch; // everything goes through this one routine NdisInitUnicodeString ( &DeviceName, NTDEVICE_STRING ); NdisInitUnicodeString ( &DeviceLinkUnicodeString, LINKNAME_STRING ); // Create a device object and register our dispatch handlers Status = NdisMRegisterDevice ( hNdisWrapper,//MiniportAdapterHandle, &DeviceName, &DeviceLinkUnicodeString, &DispatchTable[0], &ControlDeviceObject, &NdisDeviceHandle ); NdisAcquireSpinLock ( &GlobalLock ); |
|
|
6楼#
发布于:2003-07-26 13:03
king229这个家伙`~ 你想做什么~ 你才是鬼
|
|
|
7楼#
发布于:2003-07-26 13:55
king229这个家伙`~ 你想做什么~ 你才是鬼 大侠,我刚学,不要这样对我,我很伤心的, |
|
|
8楼#
发布于:2003-07-26 19:08
大侠,我刚学,不要这样对我,我很伤心的, ??????????? 有关ring0与ring3通信有好多种方法可以解决,你可以在论坛里搜索 “通信”这个关键字 有很多贴子的, 还有to yangmin26 我只是对你 喜喜` 我知道~~ 不过我好保守~~ 不告诉你~~ 无话可说而已 //////////////////////////////////////////////////////// 这是论坛上的一篇文章,你可以 专栏文章 里找到 概要 在 Windows NT 和 Windows 2000 中,内核模式驱动程序无法回调到用户模式的应用程序中。 这是设计使然。 对于要将异步事件通知应用程序的驱动程序,应用程序需要一直使用驱动程序来使 I/O 请求保持挂起状态,以便在每次发生事件时驱动程序都可以完成请求。 本文概述应用程序与驱动程序可以用来完成异步通知的典型方案。 更多信息 应用程序 应用程序可以有专用的输入线程。 线程将进入发送 I/O 请求并等待响应的循环中。 如果驱动程序已打开,并且获得 hDevice 句柄,则循环类似于如下: while (!Application exiting) { returnval = DeviceIoControl (hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpoOverlapped); if (!returnval && (GetLastError() == ERROR_IO_PENDING)) { WaitForSingleObject (hEvent, INFINITE) // hEvent is located in overlapped structure as well ... // Code to do action ResetEvent (hEvent) } { ... // Code to handle other situations } } BOOL 型 Application exiting() 代表循环应停止检查事件的条件。 如果需要退出,应用程序的主线程可以将该 BOOL 型设置为 TRUE。 I/O 控制代码 dwIoControlCode() 是由驱动程序定义的。 为使其它应用程序线程能够在该请求挂起时继续将请求发送到驱动程序,必须异步进行上述 DeviceIoControl 调用。 可以使用已被初始化的事件并传入 DeviceIoControl 调用的重叠结构中,使该线程与请求完成保持同步。 一旦事件被满足,该线程就可以通知其它应用程序线程:该事件已发出信号。 如果没有指定重叠结构,在驱动程序中处理该请求的同时,所有其它线程将被阻塞。 直到完成同步的 DeviceIoControl,其它线程才会被释放。 如果驱动程序使用读取请求发送异步事件通知,则用户模式线程还可以使用 ReadFile() 或 ReadFileEx(),而不使用 DeviceIoControl()。 驱动程序 驱动程序应当等到事件已经发生才完成 I/O 请求。当驱动程序收到 I/O 请求时,如果事件已发生且正等待被发送到应用程序,则驱动程序可以在调度例程中完成该请求。 如果没有任何等待报告的事件,驱动程序应执行下列步骤: 使用 IoMarkIrpPending() 将 Irp 标记为等待。 使用 IoSetCancelRoutine() 为 Irp 建立取消例程。 将 Irp 放在存储位置中(如队列)。 从调度例程返回 STATUS_PENDING。 以后,当事件已发生时,驱动程序可以通过它的延时过程调用 (DPC) 例程来完成挂起的请求。 完成 Irp 之前,驱动程序应使用 IoSetCancelRoutine 将取消例程地址设置为 NULL。 另一种方法是建立一个命名事件对象,让应用程序和驱动程序来共享这个事件对象。至于这个事件对象由谁来建立,没有多大关系,但一般都习惯于由驱动程序来建立。 然后应用程序端就可以等待这个事件信号状态,驱动程序想主动和应用程序通讯的时候就会置这个事件信号状态。 |
|
|
9楼#
发布于:2003-07-27 13:27
to king229:
我真的非常喜欢这个论坛上的氛围,对大侠们的无私与亮节是深感崇敬!真的非常感谢您的帮助............. |
|
|
10楼#
发布于:2003-07-27 19:15
这是最easy的和最简单的(ZT):
1.通讯 在NDIS IMD中用NdisMRegisterDevice,注册一个设备。然后可以通过 DeviceIoControl和应用层通讯 2。当你在APP调用API比如CreateFile ,等等时系统将你的请求转化为IRP转入KENEL中 IP都的定义如下: /*the internet paket header */ typedef struct{ u_char vandhl; /*contain the version and the internet packet header length*/ u_char tos; /* type of server */ u_short iplen; /* the internet length=internet header length+data */ u_short id; /* datagram id use to caption the only datagram */ u_short flags; /*commonly is zero */ u_char ttl; /* time to live */ u_char ipp; /* the next pocotol is udp or tcp */ u_short cksum; /* Internet header checksum */ u_long saddr; /* the source ip address */ u_long daddr; /* detination addresss */ }iphdr; /////////////////////////////////////////////////////////// w2k下的PassThru和用户态交互修改说明 一.参考资料为winXP DDK下的PassThru。如果熟悉的话就不要浪费时间看我的修改过程(太简陋了,怕大家笑话),很容易搞定的。 二.内核态的修改过程: 1.在Passthru.c中增加如下的变量定义 #define LINKNAME_STRING L\"\\\\DosDevices\\\\Passthru\" #define NTDEVICE_STRING L\"\\\\Device\\\\Passthru\" NDIS_HANDLE NdisDeviceHandle = NULL; PDEVICE_OBJECT ControlDeviceObject = NULL; enum _DEVICE_STATE { PS_DEVICE_STATE_READY = 0, // ready for create/delete PS_DEVICE_STATE_CREATING, // create operation in progress PS_DEVICE_STATE_DELETING // delete operation in progress } ControlDeviceState = PS_DEVICE_STATE_READY; /////////////////////////////////////////////////////////////////////////////////////// 2.在Passthru.c增加如下函数 NDIS_STATUS PtRegisterDevice( VOID ) /*++ Routine Description: Register an ioctl interface - a device object to be used for this purpose is created by NDIS when we call NdisMRegisterDevice. This routine is called whenever a new miniport instance is initialized. However, we only create one global device object, when the first miniport instance is initialized. This routine handles potential race conditions with PtDeregisterDevice via the ControlDeviceState and MiniportCount variables. NOTE: do not call this from DriverEntry; it will prevent the driver from being unloaded (e.g. on uninstall). Arguments: None Return Value: NDIS_STATUS_SUCCESS if we successfully register a device object. --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; UNICODE_STRING DeviceName; UNICODE_STRING DeviceLinkUnicodeString; PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION]; UINT i; DBGPRINT((\"==>PtRegisterDevice\\n\")); NdisAcquireSpinLock(&GlobalLock); ++MiniportCount; if (1 == MiniportCount) { ASSERT(ControlDeviceState != PS_DEVICE_STATE_CREATING); // // Another thread could be running PtDeregisterDevice on // behalf of another miniport instance. If so, wait for // it to exit. // while (ControlDeviceState != PS_DEVICE_STATE_READY) { NdisReleaseSpinLock(&GlobalLock); NdisMSleep(1); NdisAcquireSpinLock(&GlobalLock); } ControlDeviceState = PS_DEVICE_STATE_CREATING; NdisReleaseSpinLock(&GlobalLock); for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DispatchTable = PtDispatch; } NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING); NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING); // // Create a device object and register our dispatch handlers // Status = NdisMRegisterDevice( NdisWrapperHandle, &DeviceName, &DeviceLinkUnicodeString, &DispatchTable[0], &ControlDeviceObject, &NdisDeviceHandle ); NdisAcquireSpinLock(&GlobalLock); ControlDeviceState = PS_DEVICE_STATE_READY; } NdisReleaseSpinLock(&GlobalLock); //DBGPRINT((\"<==PtRegisterDevice: %x\\n\", Status)); DBGPRINT(\"<==PtRegisterDevice\"); return (Status); } NTSTATUS PtDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Process IRPs sent to this device. Arguments: DeviceObject - pointer to a device object Irp - pointer to an I/O Request Packet Return Value: NTSTATUS - STATUS_SUCCESS always - change this when adding real code to handle ioctls. --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status = STATUS_SUCCESS; DBGPRINT((\"==>Pt Dispatch\\n\")); irpStack = IoGetCurrentIrpStackLocation(Irp); switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: break; case IRP_MJ_CLOSE: break; case IRP_MJ_DEVICE_CONTROL: // // Add code here to handle ioctl commands sent to passthru. // break; default: break; } Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); DBGPRINT((\"<== Pt Dispatch\\n\")); return status; } NDIS_STATUS PtDeregisterDevice( VOID ) /*++ Routine Description: Deregister the ioctl interface. This is called whenever a miniport instance is halted. When the last miniport instance is halted, we request NDIS to delete the device object Arguments: NdisDeviceHandle - Handle returned by NdisMRegisterDevice Return Value: NDIS_STATUS_SUCCESS if everything worked ok --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; DBGPRINT((\"==>PassthruDeregisterDevice\\n\")); NdisAcquireSpinLock(&GlobalLock); ASSERT(MiniportCount > 0); --MiniportCount; if (0 == MiniportCount) { // // All miniport instances have been halted. Deregister // the control device. // ASSERT(ControlDeviceState == PS_DEVICE_STATE_READY); // // Block PtRegisterDevice() while we release the control // device lock and deregister the device. // ControlDeviceState = PS_DEVICE_STATE_DELETING; NdisReleaseSpinLock(&GlobalLock); if (NdisDeviceHandle != NULL) { Status = NdisMDeregisterDevice(NdisDeviceHandle); NdisDeviceHandle = NULL; } NdisAcquireSpinLock(&GlobalLock); ControlDeviceState = PS_DEVICE_STATE_READY; } NdisReleaseSpinLock(&GlobalLock); //DBGPRINT((\"<== PassthruDeregisterDevice: %x\\n\", Status)); DBGPRINT(\"<== PassthruDeregisterDevice\"); return Status; } VOID PtUnloadProtocol( VOID ) { NDIS_STATUS Status; if (ProtHandle != NULL) { NdisDeregisterProtocol(&Status, ProtHandle); ProtHandle = NULL; } DBGPRINT((\"PtUnloadProtocol: done!\\n\")); } /////////////////////////////////////////////////////////////////////////////////////// 3.在passthru.h文件中增加上述函数的声明 NTSTATUS PtDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NDIS_STATUS PtRegisterDevice( VOID ); NDIS_STATUS PtDeregisterDevice( VOID ); VOID PtUnloadProtocol( VOID ); ///////////////////////////////////////////////////////////////////////////////////// 4.在precomp.h文件的第一行增加如下定义 #define NDIS_WDM 1 ///////////////////////////////////////////////////////////////////////////////////// 5.把passthru.c文件中的函数DriverEntry中的PChars.UnloadHandler = NULL;改为 PChars.UnloadHandler = PtUnloadProtocol; ///////////////////////////////////////////////////////////////////////////////////// 6.在miniport.h文件中的函数MPInitialize的代码:Status = NDIS_STATUS_SUCCESS;前增加 // // Create an ioctl interface // (VOID)PtRegisterDevice(); ///////////////////////////////////////////////////////////////////////////////////// 7.在miniport.h文件中的函数MPHalt的代码:if (pAdapt->BindingHandle != NULL)前增加 NdisReleaseSpinLock(&GlobalLock); // // Delete the ioctl interface that was created when the miniport // was created. // (VOID)PtDeregisterDevice(); ///////////////////////////////////////////////////////////////////////////////////// 8.把protocol.c文件中的函数PtUnload的内容改为如下: DBGPRINT((\"PtUnload: entered\\n\")); PtUnloadProtocol(); DBGPRINT((\"PtUnload: done!\\n\")); ///////////////////////////////////////////////////////////////////////////////////// 9.把passthru.c文件中的函数DriverEntry的变量定义的后面加上如下代码: NdisAllocateSpinLock(&GlobalLock); ///////////////////////////////////////////////////////////////////////////////////// 10.修改完毕后编译装载并重起机器就可以了. 三.用户态的代码很简单如下: #include \"stdafx.h\" #include <windows.h> #include <stdio.h> int main(int argc, char* argv[]) { HANDLE hdevice = CreateFile(\"\\\\\\\\.\\\\Passthru\", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hdevice == INVALID_HANDLE_VALUE) { printf(\"Unable to open PassThru device - error %d\\n\", GetLastError()); return 1; } CloseHandle(hdevice); return 0; } 运行用户态程序,用DebugView就可以看到内核态和用户态的交互情况。 祝你好运! 不用说什么“高风亮节”什么的,大家互相帮组而已。。 :D :D :D :D :D :D :D :D :D :D :D |
|
|
11楼#
发布于:2003-07-28 09:20
不罗嗦了,给分
|
|
|