Как сделать kill (pid, SIGINT) в окнах? [Дубликат]

Это очень распространенная проблема, с которой мы сталкиваемся, борясь с «таинствами» JavaScript.

Давайте начнем с простой функции JavaScript:

function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here

Это простой синхронный вызов функции (где каждая строка кода выполняется одна за другой в последовательность), и результат будет таким же, как ожидалось.

Теперь добавим немного завихрения, введя небольшую задержку в нашей функции, чтобы все строки кода не выполнялись последовательно. Таким образом, он будет эмулировать асинхронное поведение функции:

function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

Итак, вы идете, эта задержка просто сломала функциональность, которую мы ожидали! Но что именно произошло? Ну, на самом деле это довольно логично, если вы посмотрите на код. функция foo() после выполнения ничего не возвращает (таким образом, возвращаемое значение равно undefined), но оно запускает таймер, который выполняет функцию после 1s, чтобы вернуть «wohoo». Но, как вы можете видеть, значение, присвоенное бару, является немедленно возвращенным материалом из foo (), а не что-либо еще, что приходит позже.

Итак, как мы решаем эту проблему?

Давайте попросим нашу функцию для ОБЕЩАНИЯ. Обещание действительно о том, что это означает: это означает, что функция гарантирует, что вы предоставите любой результат, который он получит в будущем. поэтому давайте посмотрим на это в нашей маленькой проблеме выше:

function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when exececution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});

Таким образом, резюме - для решения асинхронных функций, таких как вызовы на основе ajax и т. д., вы можете использовать обещание resolve значение (которое вы намерены вернуть). Таким образом, короче говоря, вы разрешаете значение вместо возврата в асинхронных функциях.

73
задан JasonMArcher 18 May 2015 в 17:23
поделиться

10 ответов

Самое близкое, что я пришел к решению, это SendSignal стороннее приложение. Автор перечисляет исходный код и исполняемый файл. Я проверил, что он работает под 64-битными окнами (работает как 32-разрядная программа, убивая еще одну 32-разрядную программу), но я не понял, как вставлять код в программу Windows (либо 32-разрядную или 64-бит).

Как это работает:

После многократного поиска в отладчике я обнаружил, что точка входа, которая фактически выполняет поведение, связанное с сигналом, как ctrl-break - это kernel32! CtrlRoutine. Функция имела тот же прототип, что и ThreadProc, поэтому его можно использовать непосредственно с CreateRemoteThread, без необходимости вводить код. Однако это не экспортированный символ! Он находится на разных адресах (и даже имеет разные имена) в разных версиях Windows. Что делать?

Вот решение, которое я, наконец, придумал. Я устанавливаю консольный обработчик ctrl для своего приложения, а затем генерирую сигнал ctrl-break для моего приложения. Когда мой обработчик вызван, я оглядываюсь наверху стека, чтобы узнать параметры, переданные в kernel32! BaseThreadStart. Я беру первый параметр, который является желаемым начальным адресом потока, который является адресом kernel32! CtrlRoutine. Затем я возвращаюсь из своего обработчика, указывая, что я обработал сигнал, и мое приложение не должно быть прекращено. Вернемся в основной поток, я жду, пока не будет найден адрес ядра32! CtrlRoutine. Как только у меня получится, я создаю удаленный поток в целевом процессе с открытым начальным адресом. Это приводит к тому, что обработчики ctrl в целевом процессе оцениваются так, как если бы был нажат ctrl-break!

Приятно, что затрагивается только целевой процесс, и любой процесс (даже оконный процесс) может быть целенаправленным. Один недостаток заключается в том, что мое маленькое приложение не может использоваться в пакетном файле, так как оно убьет его, когда он отправит событие ctrl-break, чтобы обнаружить адрес kernel32! CtrlRoutine.

(запустите его с помощью start, если он запущен в пакетном файле.)

26
ответ дан Vadzim 27 August 2018 в 22:00
поделиться

Вот код, который я использую в своем приложении на C ++.

Положительные точки:

  • Работает с консольным приложением
  • Работает с сервисом Windows
  • Не требуется задержка
  • Не закрывает текущее приложение

Отрицательные точки:

  • Основная консоль потерянный и новый (см. FreeConsole )
  • Переключение консоли дает странные результаты ...

// Inspired from http://stackoverflow.com/a/15281070/1529139
// and http://stackoverflow.com/q/40059902/1529139
bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent)
{
    bool success = false;
    DWORD thisConsoleId = GetCurrentProcessId();
    // Leave current console if it exists
    // (otherwise AttachConsole will return ERROR_ACCESS_DENIED)
    bool consoleDetached = (FreeConsole() != FALSE);

    if (AttachConsole(dwProcessId) != FALSE)
    {
        // Add a fake Ctrl-C handler for avoid instant kill is this console
        // WARNING: do not revert it or current program will be also killed
        SetConsoleCtrlHandler(nullptr, true);
        success = (GenerateConsoleCtrlEvent(dwCtrlEvent, 0) != FALSE);
        FreeConsole();
    }

    if (consoleDetached)
    {
        // Create a new console if previous was deleted by OS
        if (AttachConsole(thisConsoleId) == FALSE)
        {
            int errorCode = GetLastError();
            if (errorCode == 31) // 31=ERROR_GEN_FAILURE
            {
                AllocConsole();
            }
        }
    }
    return success;
}

Пример использования:

DWORD dwProcessId = ...;
if (signalCtrl(dwProcessId, CTRL_C_EVENT))
{
    cout << "Signal sent" << endl;
}
3
ответ дан 56ka 27 August 2018 в 22:00
поделиться

На основе идентификатора процесса мы можем отправить сигнал для обработки для принудительного или грациозного прекращения или любого другого сигнала.

Список всех процессов:

C:\>tasklist

Чтобы убить процесс :

C:\>Taskkill /IM firefox.exe /F
or
C:\>Taskkill /PID 26356 /F

Подробности:

http://tweaks.com/windows/39559/kill-processes-from-command-prompt/

2
ответ дан Awanish Kumar 27 August 2018 в 22:00
поделиться

В Java, используя JNA с библиотекой Kernel32.dll, похож на C ++-решение. Запускает основной метод CtrlCSender как процесс, который просто получает консоль процесса для отправки события Ctrl + C и генерирует событие. Когда он запускается отдельно без консоли, событие Ctrl + C не нужно отключать и снова активировать.

CtrlCSender.java - На основе Nemo1024's и KindDragon's .

Учитывая известный идентификатор процесса, это консольное приложение будет прикреплять консоль целевого процесса и генерировать на нем событие CTRL + C.

import com.sun.jna.platform.win32.Kernel32;    

public class CtrlCSender {

    public static void main(String args[]) {
        int processId = Integer.parseInt(args[0]);
        Kernel32.INSTANCE.AttachConsole(processId);
        Kernel32.INSTANCE.GenerateConsoleCtrlEvent(Kernel32.CTRL_C_EVENT, 0);
    }
}

Основное приложение - Выполняет CtrlCSender как отдельный процесс утешения

ProcessBuilder pb = new ProcessBuilder();
pb.command("javaw", "-cp", System.getProperty("java.class.path", "."), CtrlCSender.class.getName(), processId);
pb.redirectErrorStream();
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Process ctrlCProcess = pb.start();
ctrlCProcess.waitFor();
16
ответ дан Community 27 August 2018 в 22:00
поделиться

Как-то GenerateConsoleCtrlEvent() возвращает ошибку, если вы вызываете ее для другого процесса, но можете подключиться к другому консольному приложению и отправить событие ко всем дочерним процессам.

void SendControlC(int pid)
{
    AttachConsole(pid); // attach to process console
    SetConsoleCtrlHandler(NULL, TRUE); // disable Control+C handling for our app
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // generate Control+C event
}
45
ответ дан KindDragon 27 August 2018 в 22:00
поделиться

Я нашел все это слишком сложным и использовал SendKeys для отправки нажатия CTRL-C в окно командной строки (то есть окно cmd.exe) в качестве обходного пути.

1
ответ дан Mwizak 27 August 2018 в 22:00
поделиться

Изменить:

Для приложения GUI «нормальный» способ справиться с этим при разработке Windows - это отправить сообщение WM_CLOSE в главное окно процесса.

Для console app, вам нужно использовать SetConsoleCtrlHandler , чтобы добавить CTRL_C_EVENT.

Если приложение не соблюдает это, вы можете вызвать TerminateProcess .

6
ответ дан Reed Copsey 27 August 2018 в 22:00
поделиться

Это должно быть прозрачным, потому что в данный момент это не так. Существует модифицированная и скомпилированная версия SendSignal для отправки Ctrl-C (по умолчанию она отправляет Ctrl + Break). Вот несколько бинарных файлов:

(2014-3-7): я построил 32-битную и 64-битную версию с помощью Ctrl-C, это называется SendSignalCtrlC.exe, и вы можете скачать ее на : https://dl.dropboxusercontent.com/u/49065779/sendsignalctrlc/x86/SendSignalCtrlC.exe https://dl.dropboxusercontent.com/u/49065779/sendsignalctrlc/x86_64/ SendSignalCtrlC.exe - Juraj Michalak

Я также отразил эти файлы на всякий случай: 32-разрядная версия: https://www.dropbox.com/ s / r96jxglhkm4sjz2 / SendSignalCtrlC.exe? dl = 0 64-разрядная версия: https://www.dropbox.com/s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0

Отказ от ответственности: я не создал эти файлы. Скомпилированные исходные файлы не были внесены. Единственной протестированной платформой является 64-разрядная Windows 7. Рекомендуется адаптировать исходный код, доступный в http://www.latenighthacking.com/projects/2003/sendSignal/ , и скомпилировать его самостоятельно.

3
ответ дан rogerdpack 27 August 2018 в 22:00
поделиться

Друг мой предложил совершенно другой способ решения проблемы, и это сработало для меня. Используйте vbscript, как показано ниже. Он запускается и запускается, запускается в течение 7 секунд и закрывает его с помощью ctrl + c.

'Пример VBScript

Set WshShell = WScript.CreateObject("WScript.Shell")

WshShell.Run "notepad.exe"

WshShell.AppActivate "notepad"

WScript.Sleep 7000

WshShell.SendKeys "^C"
1
ответ дан teo van kot 27 August 2018 в 22:00
поделиться
        void SendSIGINT( HANDLE hProcess )
        {
            DWORD pid = GetProcessId(hProcess);
            FreeConsole();
            if (AttachConsole(pid))
            {
                // Disable Ctrl-C handling for our program
                SetConsoleCtrlHandler(NULL, true);

                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // SIGINT

                //Re-enable Ctrl-C handling or any subsequently started
                //programs will inherit the disabled state.
                SetConsoleCtrlHandler(NULL, false);

                WaitForSingleObject(hProcess, 10000);
            }
        }
3
ответ дан Тарик Ялауи 27 August 2018 в 22:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: