Как передать данные из драйвера в "пользовательское" приложение?

Тема в разделе "WASM.BEGINNERS", создана пользователем Inkognito, 15 май 2008.

  1. Inkognito

    Inkognito New Member

    Публикаций:
    0
    Регистрация:
    21 мар 2008
    Сообщения:
    25
    Для начала хотел передать просто какое-нибудь своё значение (число). Зделал следующее:
    определил IOCTL запрос
    Код (Text):
    1. #define IOCTL_GETPACKET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
    сделал процедуру обслуживания IOCTL запросов
    Код (Text):
    1. NTSTATUS DeviceControlRoutine( IN PDEVICE_OBJECT fdo, IN PIRP Irp )
    2. {
    3. PUCHAR IPPACKET = NULL;
    4. NTSTATUS status = STATUS_SUCCESS;
    5. PIO_STACK_LOCATION IrpStack;
    6. HANDLE hEvent;
    7.  
    8. IrpStack = IoGetCurrentIrpStackLocation (Irp);
    9. ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
    10. method = ControlCode & 0x00;
    11.  
    12. currentIrql = KeGetCurrentIrql();
    13.  
    14.     DbgPrint("In DeviceControlRoutine (fdo= %X)\n",fdo);
    15.     DbgPrint("DeviceIoControl: IOCTL %x.", ControlCode );
    16.     if(currentIrql==PASSIVE_LEVEL)
    17.         DbgPrint("-Example- PASSIVE_LEVEL (val=%d)",currentIrql);
    18.        
    19.     KeAcquireSpinLock(&MySpinLock,&irql);
    20.  
    21. switch (ControlCode )
    22. {
    23.   case IOCTL_GETPACKET:
    24.       {          
    25.         InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
    26.         DbgPrint("Buffer outlength %d \n",InputLength);
    27.     OutputLength = IrpStack->Parameters.DeviceIoControl. OutputBufferLength;       
    28.         DbgPrint("Buffer outlength %d\n",OutputLength);
    29.        
    30.         if( OutputLength < 1 )
    31.         {
    32.             status = STATUS_INVALID_PARAMETER;
    33.             DbgPrint("error buffer\n");
    34.             break;
    35.         }
    36.         if( method == METHOD_BUFFERED )
    37.         {
    38.             IPPACKET = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
    39.             DbgPrint("Method : BUFFERED.\n");
    40.         }
    41.         else
    42.             if ( method == METHOD_NEITHER )
    43.             {
    44.                 IPPACKET = (unsigned char*)Irp->UserBuffer;    
    45.                 DbgPrint("Method : NEITHER.\n");       
    46.             }
    47.             else
    48.             {          
    49.                 DbgPrint("Method : unsupported.\n");       
    50.                 status = STATUS_INVALID_DEVICE_REQUEST;
    51.                 break;
    52.             }      
    53.         DbgPrint("-Example- Buffer address is %08X \n",IPPACKET);
    54.        
    55.           *IPPACKET = (UCHAR)0x33; // произвольное значение
    56.         break;
    57.       }
    58.   default:
    59.       {
    60.          Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
    61.               break;
    62.       };
    63. };
    64.         KeReleaseSpinLock(&MySpinLock,irql);
    65.         DbgPrint("DeviceIoControl: %d bytes written.", (int)BytesTxd);
    66.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
    67.  
    68.  return status;
    69. }
    в приложении делаю следующее
    Код (Text):
    1. HANDLE hHandle;
    2. DWORD BytesReturned;
    3. unsigned long ioctlCode = IOCTL_GETPACKET;
    4. unsigned char packet = 0x88; // произвольное значение
    5.  
    6. int main(int argc, char* argv[])
    7. {
    8.   hHandle = CreateFile(...);
    9.   if( !DeviceIoControl(   hHandle,
    10.                     IOCTL_GETPACKET,
    11.                     NULL, 0,    // Input
    12.                     &packet, sizeof(packet),    // &packet, sizeof(packet),
    13.                     &BytesReturned,
    14.                     NULL )  )
    15.     {
    16.         printf( "Error in IOCTL_GETPACKET! (%d)\n", GetLastError() );
    17.         goto done;
    18.     }
    19.  printf("IOCTL_GETPACKET: BytesReturned = %d packet = %d\n",BytesReturned, packet);
    20. }
    В итоге ничего не передаётся и GetLastError() возвращает 87. Подскажите, пожалуйста, почему так происходит?
     
  2. steelfactor

    steelfactor New Member

    Публикаций:
    0
    Регистрация:
    26 апр 2007
    Сообщения:
    501
    исправь
    Код (Text):
    1. method = ControlCode & 0x00
    на
    Код (Text):
    1. method = ControlCode & 0x03
    Потом - CreateFile() нормально вызывается?
     
  3. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    1)
    LPC, shared memory, pipes

    2)
    Код (Text):
    1. switch (ControlCode )
    2. {
    3.   case IOCTL_GETPACKET:
    дальше нет смысла проверят ьmethod - всегда будет buffered, как это и прописано в CTL_CODE при объявлении IOCTL_GETPACKET.

    3) код никогда не выполнится в силу 2), но все же:
    Код (Text):
    1.             IPPACKET = (unsigned char*)Irp->UserBuffer;    
    2.                 DbgPrint("Method : NEITHER.\n");       
    3. ...
    4.           *IPPACKET = (UCHAR)0x33; // произвольное значение
    и это при IRQL=2 (не забывай - ты удерживаешь spin lock!) - дело закончится, вероятно, бсодом, если вдруг юзермодный буффер окажется выгруженным в своп.

    4)
    никогда по дефолту не ориентируйся на успех.
    status = STATUS_UNSUCCESSFUL, а уж если все действительно прошло хорошо, то можно явно записать STATUS_SUCCESS туда.

    5)
    а в других случаях Status записывать в IO_STATUS_BLOCK уже не нужно чтоль?) тем более, если он у тебя STATUS_SUCCESS.
    и ты еще удивляешься, откуда GetLastError() != 0

    6) исправь опечатку как сказали в посте #2, но все равно, как я уже писал в 2), это не нужно.
     
  4. Inkognito

    Inkognito New Member

    Публикаций:
    0
    Регистрация:
    21 мар 2008
    Сообщения:
    25
    Уверен, что нужно только я не знаю как правильно это зделать, внутри case судя по всему, да? Там же и в Irp->IoStatus.Information нужно что-то записывать: 0 или что? Я написал так:
    Код (Text):
    1.    
    2. Irp->IoStatus.Status = status;
    3. Irp->IoStatus.Information = 0;
    Также убрал ненужный код, "исправил" Status, ничего не изменилось: GetLastError() = 87.
    А можно пояснить, что сие значит, а то я вообще ничего из этого не понял.
     
  5. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    И в результате Диспетчер ввода-вывода подумал, что ничего не скопировано.

    В исходнике \DDK\src\general\ioctl\ дан правильный и работающий пример использования всех методов в/в.
     
  6. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    нет, прямо перед IoCompleteRequest.
    в Information нужно записать количество байт которые ты возаращаешь - еденицу. есесно только в случае успеха
    LPC == Local Procedure Call - механизм локальной (в пределах одного компа) передачи сообщений между процессами. Своеобразная IPC. Драйвер пишет данные в определенный порт через ZwRequestWaitReplyPort, а юзермодный LPC-Сервер считывает данные.

    Shared Memory - разделяемая память, область памяти, которой владеет и программа и драйвер. Если тебе надо чето передать - то пиши туда драйвером, а юзермодная прога считает оттуда.

    Pipe - пайп - именованные каналы, механизм, похожий на LPC внешне (возможности другие, но для этого дела тоже пригодится). принцип такой же - драйвер пишет в пайп, а юзермодный сервер читает оттуда.

    Насчет твоего: нужно переписать примерно так

    Код (Text):
    1. NTSTATUS DeviceControlRoutine( IN PDEVICE_OBJECT fdo, IN PIRP Irp )
    2. {
    3.     PUCHAR IPPACKET = NULL;
    4.     NTSTATUS status = STATUS_UNSUCCESSFUL;
    5.     PIO_STACK_LOCATION IrpStack;
    6.     HANDLE hEvent;
    7.  
    8.     IrpStack = IoGetCurrentIrpStackLocation (Irp);
    9.     ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
    10.  
    11.     DbgPrint("In DeviceControlRoutine (fdo= %X)\n",fdo);
    12.     DbgPrint("DeviceIoControl: IOCTL %x.", ControlCode );
    13.        
    14.     KeAcquireSpinLock(&MySpinLock,&irql);
    15.  
    16.     Irp->IoStatus.Information = 0;  // потом перезапишем в случае успеха
    17.  
    18.     switch (ControlCode )
    19.     {
    20.         case IOCTL_GETPACKET:
    21.             InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
    22.             DbgPrint("Buffer input length %d \n",InputLength); 
    23.  
    24.             OutputLength = IrpStack->Parameters.DeviceIoControl. OutputBufferLength;       
    25.             DbgPrint("Buffer output length %d\n",OutputLength);
    26.  
    27.             if( OutputLength < 1 )
    28.             {
    29.                 status = STATUS_BUFFER_TOO_SMALL;
    30.                 DbgPrint("error buffer\n");
    31.                 break;
    32.             }
    33.  
    34.             IPPACKET = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
    35.             DbgPrint("-Example- Buffer address is %08X \n",IPPACKET);
    36.  
    37.             *IPPACKET = (UCHAR)0x33; // произвольное значение
    38.  
    39.             status = STATUS_SUCCESS;
    40.             Irp->IoStatus.Information = 1; // 1 byte
    41.  
    42.             break;
    43.       default:
    44.             status = STATUS_INVALID_DEVICE_REQUEST;
    45.     }
    46.  
    47.     KeReleaseSpinLock(&MySpinLock,irql);
    48.  
    49.     Irp->IoStatus.Status = status;
    50.     // Information уже заполнена
    51.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
    52.  
    53.     return status;
    54. }
    PS. GetLastError 87 - это The parameter is incorrect.
    Твой дров возвращал STATUS_INVALID_PARAMETER
     
  7. Inkognito

    Inkognito New Member

    Публикаций:
    0
    Регистрация:
    21 мар 2008
    Сообщения:
    25
    Я наверное совсем плохой у меня в каталоге D:\WINDDK\2600\src\general\ нет папки ioctl, где можно ещё посмотреть правильный и работающий пример использования всех методов в/в.
    А ошибка точно в драйвере, может быть DeviceIoControl() как-нибудь коряво (у меня наверное всё коряво, но я вроде по книжке делаю) вызвана в приложении?
     
  8. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Inkognito
    http://ifolder.ru/6603246
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    у меня тоже ))
     
  10. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Этого не может быть. Этот пример есть во всех ддк. Может чуть в другой каталог угодил. Приаттаченный из IFS Kit 2003 Server.
     
  11. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Four-F
    я каталог этот, который выше запостил, из WDK взял...
    насчёт DDK не знаю :dntknw:
     
  12. Inkognito

    Inkognito New Member

    Публикаций:
    0
    Регистрация:
    21 мар 2008
    Сообщения:
    25
    Всем спасибо за участие, сейчас буду изучать! Вот только чем открыывать файл ioctl.7z
     
  13. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Inkognito
    бесплатная альфа, но не глючная :)
    http://ifolder.ru/6603579
     
  14. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Мож я чего упустил, но на офсайте уже 4.57 свободно лежит http://www.7-zip.org/. WinRAR (у меня 3.71) 7зипы тоже без проблем берёт.
     
  15. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Four-F
    нет это я с этими архиваторами упустил :)
    поставил, работает да и ладно...
     
  16. Inkognito

    Inkognito New Member

    Публикаций:
    0
    Регистрация:
    21 мар 2008
    Сообщения:
    25
    Люди добрые, если не трудно, поделитесь пожалуйста вот этим DDK\src\general\event примером, а то я человек несведующий, никак найти не могу. И ещё здесь же на форуме было написано
    Можно подробнее пояснить, что значит наоборот и когда иногда?
     
  17. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Four-F
    Кстати она до сих пор beta. Я ждал ждал, да и стал юзать. Есть много приятных моментов.
     
  18. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Эта техника известна как Inverted Call.

    Юзер открывает хендл девайса для ассинхронного в/в CreateFile(..FILE_FLAG_OVERLAPPED..), создает отдельный поток(и) (хотя в самом простом случае можно и в основном потоке), и в этом потоке в цикле опрашивает драйвер. Кидает драйверу буфер(ы) через ReadFile(Ex) или DeviceIoControl. Если у драйвера есть данные, то они сразу возвращаются в буфере, если нет, то драйвер ставит запрос в очередь, но IRP завершает со статусом STATUS_PENDING, что приводит к засыпанию юзерного потока. Когда у драйвера появятся данные, то он достает запрос из очереди, копирует данные в буфер и завершает запрос, что автоматически приводит к пробуждению юзерного потока. Обработав данные, юзерный поток опять кидает драйверу буфер и засыпает.

    В случае синхронизации по событию главная проблема в том, что невозможно одновременно с сигналом передать хоть какой-то буфер, а это нужно практически всегда. Поэтому сразу после сигнала события следует вызов ReadFile или DeviceIoControl. Т.о. получаем две фазы обмена user-kernel: первая - сигнал от события, вторая - обмен данными. Inverted Call избавляет от одной фазы, т.е. от события. Так что если нужен обмен данными, то лучше юзать Inverted Call.

    Правда, реализация Inverted Call значительно сложнее. Нужно понимать еще две базовые техники: очередь IRP (IRP Queue) и отмена IRP (IRP Cancellation). Они используются драйвером для организации Inverted Call. В исходнике cancell всё это есть и вроде относительно подробно описано в DDK.
     
  19. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    А можно заюзать LPC ))
    Там как раз приход события и передача данных связаны.
     
  20. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    извраты :)
    шаред мемори + два евента = просто, быстро, удобно, синхронно, документированно
    главное - чтобы забирающий юзер-модный поток нигде не подвисал