Drag'n'Drop файлов в консольное окно
Очередная порция странного. На этот раз я решил попробовать реализовать обработку перетаскивания файлов в консольное окно. Для обычных GUI-приложений с этим нет вообще никаких сложностей, а вот с консольными приложениями придется повозиться. Вопреки тиражируемым в этих ваших интернетах статьям, с консольными окнами не работают никакие стандартные способы перетаскивания данных типа манипулирования с расширенными стилями консольного окна WS_EX_ACCEPTFILES, с принудительным назначением ему DragAcceptFiles, с субклассированием на предмет обработки сообщения WM_DROPFILES или даже через реализацию интерфейса IDropTarget. Ни-че-го. В тоже время, если открыть системный командный интерпретатор cmd.exe и попытаться перетащить на его консольное окно какой-нибудь файл из Проводника или файлового менеджера, то в командной строке появится полный путь к этому файлу. Значит какие-то зачатки технологии Drag'n'Drop для консольных окон все-таки имеются.С помощью обработки событий консоли удалось выяснить, что при перетаскивании файла в консольное окно, путь к нему передается посимвольно через события KEY_EVENT. При более детальном анализе я также выяснил, что четкой системы тут нет, часть символов передается с событием нажатия и отпускания клавиши, а часть только с отпусканием клавиш. Единственные закономерности заключаются в том, что такие символы передаются обязательно со счетчиком повторений равным 1 и точно с флагом отпускания клавиш.
Также не стоит забывать про различные программы-обработчики клавиатуры типа Punto Switcher, которые самостоятельно обрабатывают введенные символы и затем могут менять их раскладку и последовательность через эмуляцию ввода с клавиатуры.
Опытным путем удалось подобрать работоспособную последовательность действий с очередью сообщений консоли. Проверено на Windowx XP, Windows 7 и Windows 10 разных разрядностей, все работает.
Code (Assembler) : Убрать нумерацию
- ; Получить хэндл стандартного ввода stdout
- invoke GetStdHandle,STD_OUTPUT_HANDLE
- mov [hOut],eax
- ; Получить хэндл стандартного ввода stdin
- invoke GetStdHandle,STD_INPUT_HANDLE
- mov [hIn],eax
- ; Инициализировать начальные значения
- invoke GetTickCount
- mov [timer],eax
- mov edi,buff
- loc_loop:
- invoke GetTickCount
- mov ebx,eax
- sub eax,[timer]
- ; Дельта таймера
- cmp eax,200
- jb loc_next
- ; Что-то уже удалось записать в буфер?
- invoke lstrlen,buff
- cmp eax,2
- jbe @f
- ; buff -> переданное имя файла
- ; выполнить с ним нужные действия
- @@:
- ; Сбросить буфер
- mov byte [buff],0
- mov [timer],ebx
- mov edi,buff
- loc_next:
- ; Получить количество событий в очереди
- invoke GetNumberOfConsoleInputEvents,[hIn],tmp
- cmp [tmp],0
- je loc_loop
- ; Прочитать одно событие из очереди
- invoke ReadConsoleInput,[hIn],input,1,tmp
- ; Обработка в зависимости от типа события
- cmp word [input.EventType],KEY_EVENT
- jne loc_loop
- ; Защита от автоповторов
- cmp [input.KeyEvent.wRepeatCount],1
- je @f
- ; Сбросить буфер
- invoke FlushConsoleInputBuffer,[hIn]
- mov byte [buff],0
- mov edi,buff
- @@:
- ; KEY_EVENT
- cmp [input.KeyEvent.bKeyDown],0
- jne loc_loop
- movzx eax,byte[input.KeyEvent.AsciiChar]
- cmp eax,20
- jb loc_loop
- ; Сохранить символ в буфер
- stosw
- dec edi
- jmp loc_loop
Ну и еще одно замечание. Описанным в статье методом можно обрабатывать только один файл. Множественная передача файлов через перетаскивание в консольное окно невозможна.
В приложении пример программы с исходным текстом, которая реализует обработку перетаскивания файлов в консольное окно.
Просмотров: 457 | Комментариев: 4
Метки: Assembler
Комментарии
Отзывы посетителей сайта о статье
Petya
(10.01.2024 в 18:58):
Можно пояснить, почему на усмотрение?
И, кстати, ещё одна мелкая ошибка - в слове Received буквы местами поменялись, стало Recieved.
И, кстати, ещё одна мелкая ошибка - в слове Received буквы местами поменялись, стало Recieved.
ManHunter
(10.01.2024 в 18:38):
И не должна обрабатывать, это на усмотрение разработчика.
Petya
(10.01.2024 в 18:32):
Тут есть ещё одна особенность, программа её не обрабатывает. Если в полном пути есть пробелы, то он закавычивается и перед передачей его API-функциям кавычки надо удалить.
Сделано, очевидно, ради удобства командной строки.
Сделано, очевидно, ради удобства командной строки.
Добавить комментарий
Заполните форму для добавления комментария
Ошибку поправил, спасибо. Рука дрогнула.