WM_KEYDOWN message
Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.
Parameters
The virtual-key code of the nonsystem key. See Virtual-Key Codes.
The repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown following.
Bits | Meaning |
---|---|
0-15 | The repeat count for the current message. The value is the number of times the keystroke is autorepeated as a result of the user holding down the key. If the keystroke is held long enough, multiple messages are sent. However, the repeat count is not cumulative. |
16-23 | The scan code. The value depends on the OEM. |
24 | Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0. |
25-28 | Reserved; do not use. |
29 | The context code. The value is always 0 for a WM_KEYDOWN message. |
30 | The previous key state. The value is 1 if the key is down before the message is sent, or it is zero if the key is up. |
31 | The transition state. The value is always 0 for a WM_KEYDOWN message. |
Return value
An application should return zero if it processes this message.
Example
Remarks
If the F10 key is pressed, the DefWindowProc function sets an internal flag. When DefWindowProc receives the WM_KEYUP message, the function checks whether the internal flag is set and, if so, sends a WM_SYSCOMMAND message to the top-level window. The WM_SYSCOMMAND parameter of the message is set to SC_KEYMENU.
Because of the autorepeat feature, more than one WM_KEYDOWN message may be posted before a WM_KEYUP message is posted. The previous key state (bit 30) can be used to determine whether the WM_KEYDOWN message indicates the first down transition or a repeated down transition.
For enhanced 101- and 102-key keyboards, extended keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lParam parameter.
Applications must pass wParam to TranslateMessage without altering it at all.
Могу ли я отправить ctrl-C (SIGINT) в приложение на Windows?
У меня есть (в прошлом) написанные кросс-платформенные (Windows/Unix) приложения, которые при запуске из командной строки обрабатывали пользовательский тип Ctrl — C комбинация таким же образом (т. е. для завершения приложения чисто).
возможно ли в Windows отправить Ctrl — C /SIGINT / эквивалентно процессу из другого (несвязанного) процесса, чтобы запросить, чтобы он закончился чисто (давая ему возможность привести в порядок ресурсов и т. д.)?
12 ответов:
самое близкое, что я пришел к решению-это SendSignal 3rd party app. Автор перечисляет исходный код и исполняемый файл. Я проверил, что он работает под 64-разрядной windows (работает как 32-разрядная программа, убивая другую 32-разрядную программу), но я не понял, как встроить код в программу windows (либо 32-разрядную, либо 64-разрядную).
после долгих поисков в отладчике я обнаружил, что точка входа, которая на самом деле поведение, связанное с сигналом, таким как ctrl-break, является kernel32!CtrlRoutine. Функция имела тот же прототип, что и ThreadProc, поэтому ее можно использовать с CreateRemoteThread напрямую, без необходимости вводить код. Однако это не экспортированный символ! Он находится по разным адресам (и даже имеет разные имена) в разных версиях Windows. Что же делать?
вот решение, которое я наконец придумал. Я устанавливаю обработчик ctrl консоли для своего приложения, а затем создаю ctrl-сигнал разрыва для моего приложения. Когда мой обработчик вызывается, я оглядываюсь на верхнюю часть стека, чтобы узнать параметры, переданные в kernel32!BaseThreadStart. Я беру первый param, который является желаемым начальным адресом потока, который является адресом kernel32!CtrlRoutine. Затем я возвращаюсь из своего обработчика, указывая, что я обработал сигнал, и мое приложение не должно быть прекращено. Вернувшись в основной поток, я жду, пока адрес kernel32!CtrlRoutine был извлечен. Как только я получу это, я создаю удаленный поток в целевом процессе с обнаруженным стартовым адресом. Это приводит к тому, что обработчики ctrl в целевом процессе оцениваются так, как если бы ctrl-break был нажат!
хорошая вещь заключается в том, что затрагивается только целевой процесс, и любой процесс (даже оконный процесс) может быть нацелен. Одним из недостатков является то, что мое маленькое приложение не может быть использовано в пакетном файле, так как оно убьет его, когда оно отправит событие ctrl-break, чтобы обнаружить адрес на kernel32!CtrlRoutine.
(перед ним start Если запустить его в пакетный файл.)
Я провел некоторые исследования по этой теме, которые оказались более популярными, чем я ожидал. Ответ KindDragon был одним из поворотных пунктов.
Я написал больше в блоге по этой теме и создана рабочая демонстрационная программа, которая демонстрирует использование этого типа системы для закрытия приложения командной строки в нескольких приятных модах. В этом посте также перечислены внешние ссылки, которые я использовал в своем исследовании.
короче говоря, эти демо-программы делают следующее:
- запустить программу с видимое окно, используя .Чистая, скрывает при использовании PInvoke, выполнено за 6 секунд, показать при использовании PInvoke, остановка .Нет.
- запустите программу без окна с помощью .Net, запустите в течение 6 секунд, остановитесь, подключив консоль и выдав ConsoleCtrlEvent
Edit: исправленное решение от KindDragon для тех, кто интересуется кодом здесь и сейчас. Если вы планируете запускать другие программы после остановки во-первых, вы должны повторно включить обработку Ctrl-C, иначе следующий процесс унаследует отключенное состояние родителя и не будет отвечать на Ctrl-C.
кроме того, план для решения чрезвычайных, если AttachConsole() или отправленный сигнал должен потерпеть неудачу, например спать тогда это:
Я думаю, что я немного опоздал на этот вопрос, но я все равно напишу что-нибудь для тех, у кого есть такая же проблема. Это тот же ответ, что и я дал этой вопрос.
моя проблема заключалась в том, что я хотел бы, чтобы мое приложение было графическим приложением, но выполняемые процессы должны выполняться в фоновом режиме без какого-либо интерактивного окна консоли. Я думаю, что это решение должно также работать, когда родительский процесс-это процесс консоли. Возможно, вам придется удалить Однако флаг «CREATE_NO_WINDOW».
мне удалось решить эту проблему с помощью GenerateConsoleCtrlEvent() С приложением фантик. Хитрая часть заключается в том, что документация не совсем ясно, как именно она может быть использована и подводные камни с ним.
мое решение основано на том, что описано здесь. Но это на самом деле не объясняло все детали и с ошибкой, так что вот подробности о том, как заставить его работать.
создать новый вспомогательное приложение «Помощник.исполняемый.» Это приложение будет сидеть между вашим приложением (родителем) и дочерним процессом, который вы хотите закрыть. Это также создаст фактический дочерний процесс. У вас должен быть этот процесс «среднего человека» или GenerateConsoleCtrlEvent() потерпит неудачу.
используйте какой-то механизм IPC для передачи от родителя к вспомогательному процессу, что помощник должен закрыть дочерний процесс. Когда помощник получает это событие, он вызывает » GenerateConsoleCtrlEvent(CTRL_BREAK, 0) » который закрывает себя и дочерний процесс. Я использовал объект события для этого сам, который родитель завершает, когда он хочет отменить дочерний процесс.
для создания вашего помощника.exe создать его с CREATE_NO_WINDOW и CREATE_NEW_PROCESS_GROUP. И при создании дочернего процесса создайте его без флагов (0), что означает, что он будет получать консоль от своего родителя. В противном случае это приведет к игнорированию события.
очень важно, чтобы каждый шаг был сделан вроде этого. Я пробовал все различные виды комбинаций, но эта комбинация является единственной, которая работает. Вы не можете отправить событие CTRL_C. Он вернет успех, но будет проигнорирован процессом. CTRL_BREAK является единственным, который работает. Не имеет значения, так как они оба вызова ExitProcess() в конце.
вы также не можете вызвать GenerateConsoleCtrlEvent() с идентификатором процесса groupd идентификатора дочернего процесса непосредственно позволяя вспомогательному процессу продолжать жить. Эта воля также терпеть неудачу.
Я потратил целый день, пытаясь получить эту работу. Это решение работает для меня, но если у кого есть что-нибудь добавить, пожалуйста. Я обошел всю сеть, находя много людей с похожими проблемами, но не нашел определенного решения проблемы. Как GenerateConsoleCtrlEvent () работает также немного странно, так что если кто-нибудь знает более подробную информацию об этом, пожалуйста, поделитесь.
для графического приложения «обычный» способ справиться с этим в разработке Windows-это отправить сообщение WM_CLOSE в Главное окно процесса.
для консольного приложения необходимо использовать SetConsoleCtrlHandler добавить CTRL_C_EVENT .
Если приложение не соблюдает это, вы можете позвонить TerminateProcess.
как-то GenerateConsoleCtrlEvent() возвращает ошибку, если вы вызываете ее для другого процесса, но вы можете подключиться к другому консольному приложению и отправить событие всем дочерним процессам.
Это должно быть кристально ясно, потому что на данный момент это не так. существует измененная и скомпилированная версия SendSignal для отправки Ctrl-C (по умолчанию он отправляет только Ctrl+Break). Вот некоторые двоичные файлы:
отказ от ответственности: я не создавал эти файлы. Никаких изменений не было сделано в скомпилированном виде исходный файл. Единственной проверенной платформой является 64-разрядная Windows 7. Рекомендуется адаптировать источник, доступный по адресу http://www.latenighthacking.com/projects/2003/sendSignal/ и скомпилировать его самостоятельно.
вот код, который я использую в моем приложении C++.
положительные моменты :
- работает из консольного приложения
- работает из службы Windows
- задержка не требуется
- не закрывает текущее приложение
отрицательные моменты :
- главная консоль потеряна и создана новая (см. FreeConsole)
- переключение консоли дают странные результаты.
Sending CTRL-S message to a window
I want to save a TextPad window using C# code; I can find out the handle of the window but not sure how to send CTRL — S to that window. I want to use P/Invoke API to achieve this. Also, that TextPad window will be inactive, because my application will be active at that time.
I looked at this discussion which is very similar to my problem. I understand logically that I have to do 4 send messages like below
- KeyDown CTRL key
- KeyDown S key
- KeyUp S key
- KeyUp CTRL key
I am not sure how to send the right parameters to the SendMessage. To close the window I use
I got this from MSDN library.
Can you please direct me to some link which tells me the hexadecimal for keys in the keyboard and explains what the last two parameters represent?
UPDATE — 1
Using spy++ I find these events generated with I press CTRL-S on Notepad window
This code does not work (save part of it) even though I am able to see the WM_KEYDOWN — CTRL .. WM_KEYDOWN — ‘S’ .. KEYUP ‘S’ and KEYUP CTRL being sent to the right window in spy++. Can anyone comment what is wrong with this code? Or any suggestions if I am doing something really stupid.
I should be using PostMessage instead of SendMessage as @Hans suggested in his comments.
The above code instead of CTRL+S sends CTRL and S to Notepad window. So, I can see two «S» being thrown at Notepad. Looking at the real message generated when we press CTRL+S, I see that last parameter of my Postmessage is wrong. It should be something like (for KEY UP CTRL key «C01F0001»)
Can you please tell me how to pass this hexadecimal as last parameter of postmessage?
Update 4 : I think we cannot send «hot key» messages to a minimized window. using Post Message.
This below code works with SendInput: but it will pop up the window, which kind a mar the purpose. Anyways, just wanted to update this thread.
After CTRL + S I can minimize the window but then it will create a flash. Can anyone suggest if I can achieve this functionality without the «FLASH» (at least)?
UPDATE 5 : using WM_SYSCOMMAND
I just need to send S messages to file menu which will pop up as a result of WM_SYSCOMMAND. Can anyone point me to a documentation to how to do that?
I was not able to send ^S message to a minimized window. I am using sendkeys(^s) every 2-3 seconds when the focus is on an editor.
Handle CTRL+C on Win32
I have some problems with the handling of CTRL + C events, in a Win32 C++ console program.
Basically my program looks like this: (based on this other question: Windows Ctrl-C — Cleaning up local stack objects in command line app)
The problem is the cleanup code not being executed at all.
After the execution of the handler function the process is terminated, but without execute the code after the main loop. What’s wrong?
EDIT: as requested, this is a minimal test case similar to my program: http://pastebin.com/6rLK6BU2
I don’t get the «test cleanup-instruction» string in my output.
I don’t know if this is important, I’m compiling with MinGW.
EDIT 2: The problem with the test case program is the use of the Sleep() function. Without it the program works as expected.
In Win32 the function handler runs in another thread, so when the handler/thread ends its execution the main thread is sleeping. Probably this is the cause of process interruption?
4 Answers 4
The following code works for me:
Depending on your specific requirements you have a number of options. If you simply want to ignore Ctrl + C you can call SetConsoleCtrlHandler passing NULL as the HandlerRoutine parameter:
This removes all signal handlers. To terminate this application you have to implement custom logic to determine when to shut down.
If you want to handle Ctrl + C you have two options: Set up a handler for the signal or pass the keyboard input on to regular keyboard handling.
Setting up a handler is similar to the code above, but instead of passing NULL as the handler you provide your own implementation.
The output of this application is:
Note that cleanup code is executed, regardless of the code inside the main while -loop. Signal handlers form a linked list, where the handler functions are called on a last-registered, first-called basis until one of the handlers returns TRUE . If none of the handlers returns TRUE, the default handler is called. The default handler for a console calls ExitProcess when processing Ctrl + C .
If you want to prevent any preprocessing and handle Ctrl + C as regular keyboard input instead you have to change the console mode by calling SetConsoleMode .
Once the ENABLE_PROCESSED_INPUT flag is removed Ctrl + C is no longer processed by the system and passed to the console like regular keyboard input. It can be read using ReadConsoleInput or ReadFile .
Disclaimer: The above has been tested on Windows 8 64bit, compiled for 32 and 64 bit, Release and Debug configurations.