DeviceIOControl() gives Error 50
I'm very new to communication with Windows Device Drivers.
A) I need to communicate with a third-party driver. I see that CreateFile()
accept both the device name (such as \\\\.\\DeviceName
) and also I can call the full file name (such as \\\\.\\C:\\MyPath\\DriverName.sys
). What is the best option? Why? Both works on the same way?
B) I see that many device drivers has two names, for example:
SymbolicLink "\GLOBAL??\VirtualSerial"
Destination "\Device\VrSerialrs232"
If I try open for example open VrSerialrs232
with CreateFile()
it fails. So, why is used the VrSerialrs232
if I always have to call the SymbolicLink(VirtualSerial)
?
C) I installed a DeviceIOControl
monitor to check why my code is failing with Error 50
(The request is not supported) and I can't figure why.
The output of the DeviceIOControl
monitor is here
The ones from test.exe
are my code, the other (protected) is the original application calling the same device.
My code is like this:
#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);
}
I always get this error:
C:>Test.exe
Opening.. \\.\Global\MyDeviceName
Device succesfully opened!
Error: Bytes returned 0
DeviceIOControl: Error 50 - The request is not supported
Why?
I don't know the name of the IOCTL commands, but I know the numbers. There is a way to translate a IOCTL number to a name?
This is a valid and real request that I captured with a IOCTL monitor.
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.
What I'm missing to reproduce / clone / replicate the exact same message to the same driver by from my own application?
Thanks
Typically, Windows device drivers present themselves to user mode applications by creating a symbolic link to themselves in the global namespace via IoCreateSymbolicLink().
So, it woud appear that the author of the driver in question has decided to expose this device to user mode applications, using the name "GLOBAL??\VirtualSerial". So, "\\.\VirtualSerial" (escaped) is the name your application should be using to obtain handles to the device.
User mode services do not have access to the "\Device" namespace for security reasons. This is why your user mode applications cannot open "\Device\VrSerialrs232".
Now, the return code from DeviceIOControl() indicates that the command that you're sending the device is not supported. IOCTL commands are DWORD values whose bits describe the format of the command (buffered/unbuffered, access rights required, etc.). Your best bet would be to obtain a list of the IOCTL commands for the device in question before you start working with this device. If this is a serial port type device, this would be a good place to start.
Good luck!
精彩评论