【问题标题】:DeviceIOControl() gives Error 50DeviceIOControl() 给出错误 50
【发布时间】:2010-10-15 17:08:26
【问题描述】:

我对与 Windows 设备驱动程序进行通信非常陌生。

A) 我需要与第三方驱动程序通信。我看到CreateFile() 接受设备名称(例如\\\\.\\DeviceName),我也可以调用完整的文件名(例如\\\\.\\C:\\MyPath\\DriverName.sys)。什么是最好的选择?为什么?两者的工作方式相同?

B) 我看到很多设备驱动都有两个名字,例如:

SymbolicLink "\GLOBAL??\VirtualSerial"
Destination "\Device\VrSerialrs232"

如果我尝试打开例如打开VrSerialrs232CreateFile(),它会失败。那么,如果我总是必须调用SymbolicLink(VirtualSerial),为什么还要使用VrSerialrs232

C) 我安装了一个DeviceIOControl 监视器来检查我的代码为什么会出现Error 50 失败(不支持该请求),但我不知道为什么。

DeviceIOControl 监视器的输出是here

来自test.exe 的是我的代码,另一个(受保护的)是调用同一设备的原始应用程序。

我的代码是这样的:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <strsafe.h>

void ErrorExit(LPTSTR lpszFunction){ 
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw); 
}

BOOL OpenDevice(PWSTR DriverName, HANDLE *lphDevice){

    WCHAR DeviceName[MAX_PATH]; HANDLE hDevice;

    if ((GetVersion() & 0xFF) >= 5) { 
        wcscpy(DeviceName, L"\\\\.\\Global\\");
    } else {

        wcscpy(DeviceName, L"\\\\.\\"); }
        wcscat(DeviceName, DriverName); printf("Opening.. %S\n", DeviceName);
        hDevice = CreateFileW(DeviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hDevice == INVALID_HANDLE_VALUE) {
    printf("CreateFile() ERROR %d\n", GetLastError());  return FALSE;

    }

    *lphDevice = hDevice;   return TRUE;
}

int _tmain(int argc, _TCHAR* argv[]){

 HANDLE    hDevice = NULL;
 DWORD    cb = 0;
 int ret = 0;
 char tcode[] = "\x8a\xb3\x39\x9d"; /* Copied from original request seen on Monitor) */

 if(!OpenDevice(L"MyDeviceName",&hDevice)) {

     printf("Error: Error opening device\n");   
     return(0);
 } else {

     printf("Device succesfully opened!\n");

 }

char *Buff = (char *)VirtualAlloc(NULL, 0x330, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

if (Buff){

 ret = DeviceIoControl(hDevice, 0xa028442f, tcode, 0x04, 0, NULL, &cb, (LPOVERLAPPED)NULL);

 if (ret == 0) {
   printf("Error: Bytes returned %#x\n",cb);
   ErrorExit(TEXT("DeviceIoControl: "));
    }

}

 CloseHandle(hDevice);
 return(0);
}

我总是收到这个错误:

C:>Test.exe
Opening.. \\.\Global\MyDeviceName
Device succesfully opened!
Error: Bytes returned 0
DeviceIOControl: Error 50 - The request is not supported

为什么?

我不知道 IOCTL 命令的名称,但我知道编号。有没有办法将 IOCTL 编号转换为名称?

这是我使用 IOCTL 监视器捕获的有效且真实的请求。

Log started...
'C:\PathToApplication\OriginalAppName.exe' (PID: 2896)
'\Device\VSFilterbpd' (0x86b83c40) [\??\C:\LocalPath\DeviceDriverName.sys]
SymbolicLink "\GLOBAL??\VSFFilter"
IOCTL Code: 0xa028442f,  Method: METHOD_NEITHER

    InBuff: 0x004883a4,  InSize: 0x00000004
--------------------------------------------------------------------
9c 84 e2 86                                       | ....

   OutBuff: 0x004b4f68, OutSize: 0x00001b20
--------------------------------------------------------------------
03 00 00 00 1c 03 00 00  00 00 00 00 00 00 00 00  | ................
00 00 00 00 e4 0c 00 00  00 00 00 00 00 00 00 00  | ................
A lot of data.

从我自己的应用程序复制/克隆/复制完全相同的消息到同一个驱动程序缺少什么?

谢谢

【问题讨论】:

  • 嗯,控制码错误,驱动不识别。看起来确实很奇怪,缓冲区传递方法代码是3,METHOD_NEITHER。

标签: winapi device-driver device


【解决方案1】:

通常,Windows 设备驱动程序通过IoCreateSymbolicLink() 在全局命名空间中创建指向自身的符号链接,将自身呈现给用户模式应用程序。

因此,有问题的驱动程序的作者似乎决定将此设备公开给用户模式应用程序,使用名称“GLOBAL??\VirtualSerial”。因此,“\\.\VirtualSerial”(转义)是您的应用程序用来获取设备句柄的名称。

出于安全原因,用户模式服务无权访问“\Device”命名空间。这就是您的用户模式应用程序无法打开“\Device\VrSerialrs232”的原因。

现在,DeviceIOControl() 的返回代码表明您发送设备的命令不受支持。 IOCTL 命令是 DWORD 值,其位描述命令的格式(缓冲/非缓冲、所需的访问权限等)。最好的办法是在开始使用此设备之前获取相关设备的 IOCTL 命令列表。如果这是一个串口类型的设备,this would be a good place to start

祝你好运!

【讨论】:

  • @Hans,我修复了 IOCTL 代码,现在它是正确的。 @Hans,I f ret = DeviceIoControl(hDevice, 0x86DB3F68, tcode, 0x04, 0, NULL, &cb, (LPOVERLAPPED)NULL);问题仍然存在。还有什么想法吗?您在屏幕截图中的哪里看到方法是 3?我看不到它。为什么它很奇怪?谢谢
  • 感谢您的解释,非常有帮助。我发送的命令?在这种情况下变量tcode的内容?当我调用 CreateFileW() 时,不应定义缓冲/非缓冲、所需的访问权限等?谢谢
  • 不是,它不是串行设备或相关设备。它是一种文件系统过滤器。谢谢
  • Fred,您发送的命令是 IOCTL 代码“0xa028442f”。该命令的 INPUT PAYLOAD 是一个 4 字节数组 '9c 84 e2 86'。也就是说,您可能失败的原因可能是您没有指定 OUTPUT 缓冲区(您传递的是 NULL 和 0)。有问题的 IOCTL 可能需要这个。
猜你喜欢
  • 1970-01-01
  • 2017-08-14
  • 2016-11-07
  • 2014-03-02
  • 2016-06-28
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多