阅读:3429回复:22
怎样通过DeviceControl()将驱动中的数据传输给应用程序?
大家好:
我在驱动里要做个硬件检测的功能,并在IRP_MJ_DEVICE_CONTROL分发例程中完成,应用程序通过DeviceIoControl()Win32 API取得驱动程序对硬件检测的结果,我如何在驱动中将检测后的数据传给应用程序呢? Win32 API 的 DeviceIoControl()函数的原型如下: BOOL DeviceIoControl( HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer, DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); 这里有两个参数: lpOutBuffer,nOutBufferSize,这是不是由驱动程序传输给应用程序的数据?在驱动程序里怎样将数据填入这个缓冲?我试着把数据填入Irp->UserBuffer中,但是应用程序并不能取到填入的数据。我该怎么做? |
|
|
沙发#
发布于:2002-07-19 11:49
看walter oney书的第九章
|
|
|
板凳#
发布于:2002-07-19 11:57
那两个只是缓冲区的指针
要看你在驱动中怎么用了。 |
|
|
地板#
发布于:2002-07-19 18:01
不是UserBuffer,都是SystemBuffer
|
|
地下室#
发布于:2002-07-19 22:03
这两个参数,InBuffer用于缓冲IO,OutBuffer用于直接IO,后者即可以作为输入又同时可以作为输出,如果需要输入数据,用METHOD_IN_DIRECT类型,在内核获取缓冲区的地址和长度有两种途径,一种是通过MDL,一种是通过I,两者是等效的,由于在外边上网,记不起具体的函数了,但长度的获取还是记得的,通过I.IoctlOutputBufferSize()或m_Mdl.Size()
|
|
5楼#
发布于:2002-07-19 22:10
我想起来了,用户缓冲区的地址是这样获取的,
KMemory Mem(I.Mdl()); PULONG pBuffer = (PULONG) Mem.MapToSystemSpace(); CODE的宏如下定义,0x800的位置可能与我这儿的不一样 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA) 这是直接IO方式,InBuffer即InBufferSize,这两个参数不需要,只需是NULL和0 |
|
6楼#
发布于:2002-07-20 02:17
不是UserBuffer,都是SystemBuffer ??? |
|
|
7楼#
发布于:2002-07-20 02:33
大家好: 这具体要看此时的DeviceIoControl中的参数dwIoControlCode的定义(用法),对于缓冲区的用法大体上有四种。 直接的,入,出缓冲的,非I/O 的。。。。。。。 正如这样的形式: “CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)”------------ 其每位都有含义(决定了缓冲lpInBuffer,lpOutBuffer的用法方式)。。。。。。。 “我试着把数据填入Irp->UserBuffer中,但是应用程序并不能取到填入的数据。” ---------------- 只有当你指明为“非I/O方式”时才可看到,其他的方式时不是通过Irp->UserBuffer!!! 以上只是一些提示,具体的,建议你自己再仔细看。。。。。 不懂再来。。。。 嘿嘿。。。。。 :) |
|
|
8楼#
发布于:2002-07-22 09:12
很感谢大家给我的解答,但我仍然有很多疑问:
1、请问walter oney书在哪可买到,是什么书? 2、我仍然不知道,在DeviceIoCtrol()里要怎样做才能把驱动程序里的数据传送到应用程序?能举个简单点的例子吗? 3、耽误你们的时间我深表歉意。 |
|
|
9楼#
发布于:2002-07-22 15:31
programming the windows driver model
本站好像有下的。 |
|
10楼#
发布于:2002-07-22 16:20
给你一段例程,我试过。如果有用,请给我加点分。
在用户应用程序中: void Test_BAUD_IOCTL_GETBAUD(void) { CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device CHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from device ULONG nOutput; // Count written to bufOutput // Call device IO Control interface (READ_DATA) in driver bufOutput[0]=\'w\'; bufOutput[1]=\'a\'; bufOutput[2]=\'h\'; printf(\"Received data : \"); if (!DeviceIoControl(hDevice, BAUD_IOCTL_GETBAUD, bufInput, IOCTL_INBUF_SIZE, bufOutput, IOCTL_OUTBUF_SIZE, &nOutput, NULL) ) { printf(\"ERROR: DeviceIoControl returns %0x.\", GetLastError()); exit(1); } printf(\"%s\\n\", bufOutput);*/ } 然后,在驱动程序中: NTSTATUS BaudDevice::BAUD_IOCTL_GETBAUD_Handler(KIrp I) { const char* TEST_WAH = \"TEST OK! - WAH,It\'s written by wangxdong!\"; ULONG fwLength=0; NTSTATUS status; fwLength = strlen(TEST_WAH)+1; if (I.IoctlOutputBufferSize() >= fwLength) { strcpy((PCHAR)I.IoctlBuffer(),TEST_WAH); // KMemory Mem(I.Mdl()); // strcpy((PCHAR)Mem.MapToSystemSpace(),TEST_WAH); // PVOID pa=MmGetSystemAddressForMdl(I.Mdl());//DDK的用法 // strcpy((PCHAR)pa,TEST_WAH); // strcpy((PCHAR)I.UserBuffer(),TEST_WAH); I.Information() = fwLength; status = STATUS_SUCCESS; } else { I.Information() = 0; status = STATUS_BUFFER_TOO_SMALL; } return status; } 这样,就能把驱动程序缓冲区的东西复制到应用程序中了! 应用程序执行结果显示TEST OK! - WAH,It\'s written by wangxdong! 变量 I.Information是要复制的字节数,如改为4,则只显示TEST四个字符 呵呵,我也是刚明白,大家共享一下经验! |
|
|
11楼#
发布于:2002-07-22 16:34
wangxdong 你好:
感谢你给我的回答,你说的情况(用driverstudio)确实可行,只是我现在是用ddk做驱动,实在不知道要怎么做,你能帮我吗?再次感谢你。 |
|
|
12楼#
发布于:2002-07-22 17:10
不好意思,我刚接触DS,DDK所知尚浅,帮不了你乐。
|
|
|
13楼#
发布于:2002-07-22 17:21
我还是把我所知的一二全倒出来吧,其实原理是一样的,DS只是把DDK的东西封装起来了,里面还是DDK,lpOutBuffer确实是驱动程序传递给应用程序的缓冲,它对应于驱动程序中的I.IoctlBuffer,DDK中就是AssociatedIrp.SystemBuffer ,只要这两个缓冲区设置为类型相匹配,再把IoStatus.Information设成需要传递数据的字节数,就可以了。
DDK开发的那本书有7M,不便作为附件,本站的下载区有下载,去找找吧。 |
|
|
14楼#
发布于:2002-07-22 17:40
wangxdong 你好:
我试过将驱动里的数据存入到AssociatedIrp.SystemBuffer中,然后在应用层中lpOutBuffer却没有得到相应的数据,要将AssociatedIrp.SystemBuffer做为输出缓冲(即填入该缓冲的数据应用程序可以通过lpOutBuffer取到)是不是要设置缓冲方式为“METHOD_IN_DIRECT”?我用的方式是“METHOD_BUFFERED”,是不是不正确?“METHOD_IN_DIRECT”不是只有在dma中才用的吗?我现在不是dma方式的啊? |
|
|
15楼#
发布于:2002-07-22 18:37
METHOD_BUFFERED没错,但要记得IoStatus.Information设成需要传递数据的字节数,还有两个缓冲区的类型要转换为相匹配。
|
|
|
16楼#
发布于:2002-07-22 20:40
我还是把我所知的一二全倒出来吧,其实原理是一样的,DS只是把DDK的东西封装起来了,里面还是DDK,lpOutBuffer确实是驱动程序传递给应用程序的缓冲,它对应于驱动程序中的I.IoctlBuffer,DDK中就是AssociatedIrp.SystemBuffer ,只要这两个缓冲区设置为类型相匹配,再把IoStatus.Information设成需要传递数据的字节数,就可以了。 我找不到你说的这本书,请你告诉我下载地址好吗?发到我邮箱也可以(xiehw@zhongjie.com.cn)不胜感激! |
|
|
17楼#
发布于:2002-07-23 07:44
有一点很奇怪,我作这个事情的时候,却是用AssociatedIrp.SystemBuffer怎么也无法传出,调了两天才发现用Irp->UserBuff倒对了,给你看看我的程序:
//得到参数: PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(pIrp); ULONG InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; ULONG OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; //输入: RtlCopyMemory(Buf,pIrp->AssociatedIrp.SystemBuffer,InputLength); DBuf=Buf+200; //输出: RtlCopyMemory(pIrp->UserBuffer,DBuf,OutputLength); |
|
18楼#
发布于:2002-07-23 08:47
有一点很奇怪,我作这个事情的时候,却是用AssociatedIrp.SystemBuffer怎么也无法传出,调了两天才发现用Irp->UserBuff倒对了,给你看看我的程序: 这个实验我也做过,但没有成功,我是这样做的: //在驱动中 PUCHAR OutBuffer = pIrp->UserBuffer; OutBuffer[0] = 0; OutBuffer[1] = 1; OutBuffer[2] = 2; OutBuffer[3] = 3; //在应用程序中 DWORD BytesReturned; WORD rv[4]; UCHAR ConnectToInterrupts[128]; if( DeviceIoControl( g_ZjMdmHandle, dwIoControlCode, ConnectToInterrupts, length(ConnectToInterrupts), // Input rv, sizeof(rv), // Output &BytesReturned, NULL)) return (UCHAR)BytesReturned; else return FALSE; 我希望应用程序中的rv[4]能取得驱动里OutBuffer缓冲中的四个数据“0,1,2,3”,可我失败了,请问,我应该怎么做? |
|
|
19楼#
发布于:2002-07-23 09:35
那你用这种的话缓冲方式设对没?有两个地方要设的。
我的应用程序是这样: DWORD result[32]; DWORD ret; CString str; if(WDM_Handle!=NULL) { if(!DeviceIoControl(WDM_Handle, IOCTL_READ_DDC, NULL, 0, &result, sizeof(result), &ret, NULL)) { AfxMessageBox(\"调用失败!\"); return; } } for(int i=0;i<32;i++) { str.Format(\"%x\",result); AfxMessageBox(str); } |
|
上一页
下一页