DeviceIoControl 驱动交互

驱动程序通信的函数,除了ReadFile和WriteFile函数还有DeviceIoControl函数,而且DeviceIoControl函数那是相当的彪悍。因为它可以自定义控制码,你只要在IRP_MJ_DEVICE_CONTROL对应的派遣函数中读取控制码,然后针对控制码,你就可以实现自定义的功能了。

 

函数原型:

BOOL WINAPI DeviceIoControl(

 __in         HANDLEhDevice,

 __in         DWORDdwIoControlCode,

 __in_opt     LPVOID lpInBuffer,

 __in         DWORDnInBufferSize,

 __out_opt    LPVOID lpOutBuffer,

 __in         DWORDnOutBufferSize,

 __out_opt    LPDWORD lpBytesReturned,

 __inout_opt  LPOVERLAPPED lpOverlapped

);

 

其中lpBytesReturned的值来自于IRP结构中的pIRP->IoStatus.Information。DeviceIoControl的第二个参数就是控制码,控制码是一个32为无符号整型,需要符合DDK的规定。

控制代码中各数据位字段的含义如下: 
◎ DeviceType--设备类型(31-16bit指 出了设备的类型,微软保留了0-7FFFh的取值,剩下的8000h-0FFFFh   供开发商定义新的内核模式驱动程序。我们可以在\include\w2k\ntddk.inc文件中找到一组FILE_DEVICE_XXX  符号常量,这些值都是微软保留的 值,我们可以使用其中的FILE_DEVICE_UNKNOWN。当然你也可以定义另外一个FILE_DEVICE_XXX值

◎ Access--存取代码(15-14bit指明应用程序存取设备的方式,由于这个字段只有2位,所以只有4种可能性: 

· FILE_ANY_ACCESS (0)--最大的存取权限,就是什么操作都可以 

· FILE_READ_ACCESS (1)--读权限,设备将数据传递到指定的缓冲区 

· FILE_WRITE_ACCESS (2)--写权限,可以从内存中向设备传递数据 

· FILE_READ_ACCESS or FILE_WRITE_ACCESS (3)--读写权限,设备和内存缓冲区之间可以互相传递数据 

◎ Function--功能代码(13-2bit)用来描述要进行的操作,我们可以用800h-0FFFh来定义自己的I/O控制代码,

   0-7FFh之间的值是被微软保留的,用来定义公用的I/O控制代码 

◎ Method--缓冲模式(0-1bit)表示I/O管理器如何对输入和输出的数据进行缓冲,这个字段的长度是2位,所以有

   4种可能性: 

·METHOD_BUFFERED (0)--对I/O进行缓冲 

·METHOD_IN_DIRECT (1)--对输入不进行缓冲 

·METHOD_OUT_DIRECT (2)--对输出不进行缓冲 

·METHOD_NEITHER (3)--都不缓冲 

 

缓冲区模式虽然会损失点性能,但是其安全性好。

 

下面将分别讲述这几种模式。

 

缓冲内存模式(对应代码中的IOCTL_TEST1)

首先要将控制码中的Method设置为METHOD_BUFFERED。

往驱动中Input数据:在Win32 APIDeviceIoControl函数的内部,用户提供的输入缓冲区的内容被复制到IRP的pIRP->AssociatedIrp.SystemBuffer的内存地址,复制的字节是有DeviceControl指定的输入字节数。从驱动中Output数据:派遣函数可以向pIRP->AssociatedIrp.SystemBuffer写入数据,被当做是设备输出的数据。操作系统会将AssociatedIrp.SystemBuffer的数据再次复制到DeviceIoControl提供的输出缓冲区,复制的字节数有pIrp->IoStatus.Information指定,DeviceIoControl也可以通过参数lpBytesReturned得到复制的字节数。       

原理就是这样了,理论上就可以实现读和写的双向操作了。

直接内存模式(对应代码中的IOCTL_TEST2)

首先将Method设置为METHOD_IN_DIRECT 或METHOD_OUT_DIRECT ,这两者的不同只是体现在打开设备的权限上,当以只读权限打开设备时,METHOD_IN_DIRECT 就可以顺利操作,而METHOD_OUT_DIRECT 就会失败。如果以读写权限打开时,两者都可以执行成功。

往驱动中Input数据:这部分和上面的缓冲内存模式一样,输入缓冲区的数据复制到pIrp->AssociateIrp.SystemBuffer内存地址,复制的字节数是按照DeviceIoControl指定的。

从驱动中Output数据:操作系统会为DeviceIoControl指定的输出缓冲区锁定,然后在内核模式地址下重新映射到一段地址。在派遣函数中可以先获取DeviceIoControl指定的输出缓冲区(lpOutBufferb被记录在pIrp->AssociateIrp.SystemBuffer),然后再通过MmGetSystemAddressForMdlSafe获取其在核地址中的映射值。

 

 

 

其他内存模式(对应代码中的IOCTL_TEST3)

个人觉得这种方式挺麻烦的而且少被用到,由于它是直接访问用户模式地址,要求调用DeviceIoControl的线程和派遣函数运行在同一个线程设备上下文中,自己有个印象就行了。

首先将指定的Method参数设置为METHOD_NEITHER。

往驱动中Input数据:通过I/O堆栈的Parameters.DeviceIoControl.Type3InputBuffer得到DeviceIoControl提供的输入缓冲区地址,Parameters.DeviceIoControl.InputBufferLength得到其长度。由于不能保证传递过来的地址合法,所以需要先要结果ProbeRead函数进行判断。

从驱动中Output数据:通过pIrp->UserBuffer得到DeviceIoControl函数提供的输出缓冲区地址,再通过Parameters.DeviceIoControl.OutputBufferLength得到输出缓冲区大小。同样的要用ProbeWrite函数先进行判断。

 

 

 

下面给出一个实例代码,来自于张帆的《Windows驱动开发详解》

 

首先是控制码设置:

[cpp]  view plain copy
  1. #define IOCTL_TEST1 CTL_CODE(\  
  2.   
  3.                         FILE_DEVICE_UNKNOWN, \  
  4.   
  5.                         0x800, \  
  6.   
  7.                         METHOD_BUFFERED, \  
  8.   
  9.                         FILE_ANY_ACCESS)  
  10.   
  11.    
  12.   
  13. #define IOCTL_TEST2 CTL_CODE(\  
  14.   
  15.                         FILE_DEVICE_UNKNOWN, \  
  16.   
  17.                        0x801, \  
  18.   
  19.                         METHOD_IN_DIRECT, \  
  20.   
  21.                         FILE_ANY_ACCESS)  
  22.   
  23.    
  24.   
  25. #define IOCTL_TEST3 CTL_CODE(\  
  26.   
  27.                         FILE_DEVICE_UNKNOWN, \  
  28.   
  29.                         0x802, \  
  30.   
  31.                         METHOD_NEITHER, \  
  32.   
  33.                         FILE_ANY_ACCESS)  
  34.   
  35.    
  36.   
  37. 再是IRP_MJ_DEVICE_CONTROL派遣函数:  
  38.   
  39. NTSTATUSIOCTRLDRIVER_DispatchDeviceControl(  
  40.   
  41.        IN PDEVICE_OBJECT              DeviceObject,  
  42.   
  43.        IN PIRP                                pIrp  
  44.   
  45.        )  
  46.   
  47. {  
  48.   
  49.        NTSTATUS status = STATUS_SUCCESS;  
  50.   
  51.    
  52.   
  53.        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);  
  54.   
  55.        //得到输入缓冲区大小  
  56.   
  57.        ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;  
  58.   
  59.        //得到输出缓冲区大小  
  60.   
  61.        ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;  
  62.   
  63.        //得到IOCTL码  
  64.   
  65.        ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;  
  66.   
  67.        ULONG info = 0;  
  68.   
  69.        switch(code)  
  70.   
  71.        {  
  72.   
  73.        case IOCTL_TEST1:  
  74.   
  75.                 {  
  76.   
  77.                         KdPrint(("zhui:IOCTL_TEST1\n"));  
  78.   
  79.                          
  80.   
  81.                         UCHAR* InputBuffer =(UCHAR*)pIrp->AssociatedIrp.SystemBuffer;  
  82.   
  83.                         for (ULONGi=0;i<cbin;i++)  
  84.   
  85.                         {  
  86.   
  87.                                 KdPrint(("zhui:%X\n",InputBuffer[i]));  
  88.   
  89.                         }  
  90.   
  91.    
  92.   
  93.                         //操作输出缓冲区  
  94.   
  95.                         UCHAR* OutputBuffer =(UCHAR*)pIrp->AssociatedIrp.SystemBuffer;  
  96.   
  97.                        memset(OutputBuffer,0xAA,cbout);  
  98.   
  99.                         //设置实际操作输出缓冲区长度  
  100.   
  101.                         info = cbout;  
  102.   
  103.                         break;  
  104.   
  105.                 }  
  106.   
  107.        case IOCTL_TEST2:  
  108.   
  109.                 {  
  110.   
  111.                         KdPrint(("zhui:IOCTL_TEST2\n"));  
  112.   
  113.                          
  114.   
  115.                         UCHAR* InputBuffer =(UCHAR*)pIrp->AssociatedIrp.SystemBuffer;  
  116.   
  117.                         for (ULONGi=0;i<cbin;i++)  
  118.   
  119.                         {  
  120.   
  121.                                KdPrint(("zhui:%X\n",InputBuffer[i]));  
  122.   
  123.                         }  
  124.   
  125.    
  126.   
  127.                         //pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同  
  128.   
  129.                         KdPrint(("zhui:UserAddress:0X%08X\n",MmGetMdlVirtualAddress(pIrp->MdlAddress)));  
  130.   
  131.    
  132.   
  133.                         UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);  
  134.   
  135.                         //InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间  
  136.   
  137.                        memset(OutputBuffer,0xAA,cbout);  
  138.   
  139.                         //设置实际操作输出缓冲区长度  
  140.   
  141.                         info = cbout;  
  142.   
  143.                         break;  
  144.   
  145.                 }  
  146.   
  147.        case IOCTL_TEST3:  
  148.   
  149.                 {  
  150.   
  151.                         KdPrint(("zhui:IOCTL_TEST3\n"));  
  152.   
  153.                          
  154.   
  155.                         UCHAR* UserInputBuffer= (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;  
  156.   
  157.                         KdPrint(("zhui:UserInputBuffer:0X%0X\n",UserInputBuffer));  
  158.   
  159.    
  160.   
  161.                         //得到用户模式地址  
  162.   
  163.                         PVOID UserOutputBuffer= pIrp->UserBuffer;  
  164.   
  165.    
  166.   
  167.                         KdPrint(("zhui:UserOutputBuffer:0X%0X\n",UserOutputBuffer));  
  168.   
  169.    
  170.   
  171.                         __try  
  172.   
  173.                         {  
  174.   
  175.                                KdPrint(("zhui:Enter __try block\n"));  
  176.   
  177.    
  178.   
  179.                                 //判断指针是否可读  
  180.   
  181.                                ProbeForRead(UserInputBuffer,cbin,4);  
  182.   
  183.                                 //显示输入缓冲区内容  
  184.   
  185.                                 for (ULONGi=0;i<cbin;i++)  
  186.   
  187.                                 {  
  188.   
  189.                                        KdPrint(("zhui:%X\n",UserInputBuffer[i]));  
  190.   
  191.                                 }  
  192.   
  193.    
  194.   
  195.                                 //判断指针是否可写  
  196.   
  197.                                ProbeForWrite(UserOutputBuffer,cbout,4);  
  198.   
  199.    
  200.   
  201.                                 //操作输出缓冲区  
  202.   
  203.                                memset(UserOutputBuffer,0xAA,cbout);  
  204.   
  205.    
  206.   
  207.                                 //由于在上面引发异常,所以以后语句不会被执行!  
  208.   
  209.                                 info = cbout;  
  210.   
  211.    
  212.   
  213.                                KdPrint(("zhui:Leave __try block\n"));  
  214.   
  215.                         }  
  216.   
  217.                        __except(EXCEPTION_EXECUTE_HANDLER)  
  218.   
  219.                         {  
  220.   
  221.                                KdPrint(("zhui:Catch the exception\n"));  
  222.   
  223.                                KdPrint(("zhui:The program will keep going\n"));  
  224.   
  225.                                 status =STATUS_UNSUCCESSFUL;  
  226.   
  227.                         }  
  228.   
  229.    
  230.   
  231.                         info = cbout;  
  232.   
  233.                         break;  
  234.   
  235.                 }  
  236.   
  237.        default:  
  238.   
  239.                 status =STATUS_INVALID_DEVICE_REQUEST;  
  240.   
  241.                 break;  
  242.   
  243.        }  
  244.   
  245.        pIrp->IoStatus.Status = status;  
  246.   
  247.        pIrp->IoStatus.Information = info;  
  248.   
  249.        IoCompleteRequest(pIrp, IO_NO_INCREMENT);  
  250.   
  251.        return status;  
  252.   
  253. }  


 


测试的main函数:

[cpp]  view plain copy
  1. int main()  
  2.   
  3. {  
  4.   
  5.        HANDLE hDevice =  
  6.   
  7.                CreateFile("\\\\.\\HelloDDK",  
  8.   
  9.                                        GENERIC_READ | GENERIC_WRITE,  
  10.   
  11.                                         0,              // share mode none  
  12.   
  13.                                        NULL,   // no security  
  14.   
  15.                                        OPEN_EXISTING,  
  16.   
  17.                                        FILE_ATTRIBUTE_NORMAL,  
  18.   
  19.                                         NULL);         // no template  
  20.   
  21.    
  22.   
  23.        if (hDevice == INVALID_HANDLE_VALUE)  
  24.   
  25.        {  
  26.   
  27.                 printf("Failed to obtainfile handle to device: "  
  28.   
  29.                         "%s with Win32error code: %d\n",  
  30.   
  31.                        "MyWDMDevice", GetLastError() );  
  32.   
  33.                 return 1;  
  34.   
  35.        }  
  36.   
  37.    
  38.   
  39.        UCHAR InputBuffer[10];  
  40.   
  41.        UCHAR OutputBuffer[10];  
  42.   
  43.        //将输入缓冲区全部置成0XBB  
  44.   
  45.        memset(InputBuffer,0xBB,10);  
  46.   
  47.        DWORD dwOutput;  
  48.   
  49.        //输入缓冲区作为输入,输出缓冲区作为输出  
  50.   
  51.    
  52.   
  53.        BOOL bRet;  
  54.   
  55.        bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10,&OutputBuffer, 10, &dwOutput, NULL);  
  56.   
  57.        if (bRet)  
  58.   
  59.        {  
  60.   
  61.                 printf("Output buffer:%dbytes\n",dwOutput);  
  62.   
  63.                 for (inti=0;i<(int)dwOutput;i++)  
  64.   
  65.                 {  
  66.   
  67.                         printf("%02X",OutputBuffer[i]);  
  68.   
  69.                 }  
  70.   
  71.                 printf("\n");  
  72.   
  73.        }  
  74.   
  75.    
  76.   
  77.        bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10,&OutputBuffer, 10, &dwOutput, NULL);  
  78.   
  79.        if (bRet)  
  80.   
  81.        {  
  82.   
  83.                 printf("Output buffer:%dbytes\n",dwOutput);  
  84.   
  85.                 for (inti=0;i<(int)dwOutput;i++)  
  86.   
  87.                 {  
  88.   
  89.                         printf("%02X",OutputBuffer[i]);  
  90.   
  91.                 }  
  92.   
  93.                printf("\n");  
  94.   
  95.        }  
  96.   
  97.    
  98.   
  99.        bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10,&OutputBuffer, 10, &dwOutput, NULL);  
  100.   
  101.        if (bRet)  
  102.   
  103.        {  
  104.   
  105.                 printf("Output buffer:%dbytes\n",dwOutput);  
  106.   
  107.                 for (int i=0;i<(int)dwOutput;i++)  
  108.   
  109.                 {  
  110.   
  111.                         printf("%02X",OutputBuffer[i]);  
  112.   
  113.                 }  
  114.   
  115.                 printf("\n");  
  116.   
  117.        }  
  118.   
  119.    
  120.   
  121.        CloseHandle(hDevice);  
  122.   
  123.    
  124.   
  125.        return 0;  
  126.   
  127. }  



首先是控制码设置:

[cpp]  view plain copy
  1. #define IOCTL_TEST1 CTL_CODE(\  
  2.             FILE_DEVICE_UNKNOWN, \  
  3.             0x800, \  
  4.             METHOD_BUFFERED, \  
  5.             FILE_ANY_ACCESS)  
  6.   
  7. #define IOCTL_TEST2 CTL_CODE(\  
  8.             FILE_DEVICE_UNKNOWN, \  
  9.             0x801, \  
  10.             METHOD_IN_DIRECT, \  
  11.             FILE_ANY_ACCESS)  
  12.   
  13. #define IOCTL_TEST3 CTL_CODE(\  
  14.             FILE_DEVICE_UNKNOWN, \  
  15.             0x802, \  
  16.             METHOD_NEITHER, \  
  17.             FILE_ANY_ACCESS)  


再是IRP_MJ_DEVICE_CONTROL派遣函数:

[cpp]  view plain copy
  1. NTSTATUS IOCTRLDRIVER_DispatchDeviceControl(  
  2.     IN PDEVICE_OBJECT       DeviceObject,  
  3.     IN PIRP                 pIrp  
  4.     )  
  5. {  
  6.     NTSTATUS status = STATUS_SUCCESS;  
  7.   
  8.     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);  
  9.     //得到输入缓冲区大小  
  10.     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;  
  11.     //得到输出缓冲区大小  
  12.     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;  
  13.     //得到IOCTL码  
  14.     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;  
  15.     ULONG info = 0;  
  16.     switch(code)  
  17.     {  
  18.     case IOCTL_TEST1:  
  19.         {  
  20.             KdPrint(("zhui:IOCTL_TEST1\n"));  
  21.               
  22.             UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;  
  23.             for (ULONG i=0;i<cbin;i++)  
  24.             {  
  25.                 KdPrint(("zhui:%X\n",InputBuffer[i]));  
  26.             }  
  27.   
  28.             //操作输出缓冲区  
  29.             UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;  
  30.             memset(OutputBuffer,0xAA,cbout);  
  31.             //设置实际操作输出缓冲区长度  
  32.             info = cbout;  
  33.             break;  
  34.         }  
  35.     case IOCTL_TEST2:  
  36.         {  
  37.             KdPrint(("zhui:IOCTL_TEST2\n"));  
  38.               
  39.             UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;  
  40.             for (ULONG i=0;i<cbin;i++)  
  41.             {  
  42.                 KdPrint(("zhui:%X\n",InputBuffer[i]));  
  43.             }  
  44.   
  45.             //pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同  
  46.             KdPrint(("zhui:User Address:0X%08X\n",MmGetMdlVirtualAddress(pIrp->MdlAddress)));  
  47.   
  48.             UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);  
  49.             //InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间  
  50.             memset(OutputBuffer,0xAA,cbout);  
  51.             //设置实际操作输出缓冲区长度  
  52.             info = cbout;  
  53.             break;  
  54.         }  
  55.     case IOCTL_TEST3:  
  56.         {  
  57.             KdPrint(("zhui:IOCTL_TEST3\n"));  
  58.               
  59.             UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;  
  60.             KdPrint(("zhui:UserInputBuffer:0X%0X\n",UserInputBuffer));  
  61.   
  62.             //得到用户模式地址  
  63.             PVOID UserOutputBuffer = pIrp->UserBuffer;  
  64.   
  65.             KdPrint(("zhui:UserOutputBuffer:0X%0X\n",UserOutputBuffer));  
  66.   
  67.             __try  
  68.             {  
  69.                 KdPrint(("zhui:Enter __try block\n"));  
  70.   
  71.                 //判断指针是否可读  
  72.                 ProbeForRead(UserInputBuffer,cbin,4);  
  73.                 //显示输入缓冲区内容  
  74.                 for (ULONG i=0;i<cbin;i++)  
  75.                 {  
  76.                     KdPrint(("zhui:%X\n",UserInputBuffer[i]));  
  77.                 }  
  78.   
  79.                 //判断指针是否可写  
  80.                 ProbeForWrite(UserOutputBuffer,cbout,4);  
  81.   
  82.                 //操作输出缓冲区  
  83.                 memset(UserOutputBuffer,0xAA,cbout);  
  84.   
  85.                 //由于在上面引发异常,所以以后语句不会被执行!  
  86.                 info = cbout;  
  87.   
  88.                 KdPrint(("zhui:Leave __try block\n"));  
  89.             }  
  90.             __except(EXCEPTION_EXECUTE_HANDLER)  
  91.             {  
  92.                 KdPrint(("zhui:Catch the exception\n"));  
  93.                 KdPrint(("zhui:The program will keep going\n"));  
  94.                 status = STATUS_UNSUCCESSFUL;  
  95.             }  
  96.   
  97.             info = cbout;  
  98.             break;  
  99.         }  
  100.     default:  
  101.         status = STATUS_INVALID_DEVICE_REQUEST;  
  102.         break;  
  103.     }  
  104.     pIrp->IoStatus.Status = status;  
  105.     pIrp->IoStatus.Information = info;  
  106.     IoCompleteRequest(pIrp, IO_NO_INCREMENT);  
  107.     return status;  
  108. }  


测试的main函数:

[cpp]  view plain copy
  1. int main()  
  2. {  
  3.     HANDLE hDevice =   
  4.         CreateFile("\\\\.\\HelloDDK",  
  5.                     GENERIC_READ | GENERIC_WRITE,  
  6.                     0,      // share mode none  
  7.                     NULL,   // no security  
  8.                     OPEN_EXISTING,  
  9.                     FILE_ATTRIBUTE_NORMAL,  
  10.                     NULL );     // no template  
  11.   
  12.     if (hDevice == INVALID_HANDLE_VALUE)  
  13.     {  
  14.         printf("Failed to obtain file handle to device: "  
  15.             "%s with Win32 error code: %d\n",  
  16.             "MyWDMDevice", GetLastError() );  
  17.         return 1;  
  18.     }  
  19.   
  20.     UCHAR InputBuffer[10];  
  21.     UCHAR OutputBuffer[10];  
  22.     //将输入缓冲区全部置成0XBB  
  23.     memset(InputBuffer,0xBB,10);  
  24.     DWORD dwOutput;  
  25.     //输入缓冲区作为输入,输出缓冲区作为输出  
  26.   
  27.     BOOL bRet;  
  28.     bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);  
  29.     if (bRet)  
  30.     {  
  31.         printf("Output buffer:%d bytes\n",dwOutput);  
  32.         for (int i=0;i<(int)dwOutput;i++)  
  33.         {  
  34.             printf("%02X ",OutputBuffer[i]);  
  35.         }  
  36.         printf("\n");  
  37.     }  
  38.   
  39.     bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);  
  40.     if (bRet)  
  41.     {  
  42.         printf("Output buffer:%d bytes\n",dwOutput);  
  43.         for (int i=0;i<(int)dwOutput;i++)  
  44.         {  
  45.             printf("%02X ",OutputBuffer[i]);  
  46.         }  
  47.         printf("\n");  
  48.     }  
  49.   
  50.     bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);  
  51.     if (bRet)  
  52.     {  
  53.         printf("Output buffer:%d bytes\n",dwOutput);  
  54.         for (int i=0;i<(int)dwOutput;i++)  
  55.         {  
  56.             printf("%02X ",OutputBuffer[i]);  
  57.         }  
  58.         printf("\n");  
  59.     }  
  60.   
  61.     CloseHandle(hDevice);  
  62.   
  63.     return 0;  
  64. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值