C++Builder: Завершение процесса через имя исполняемого файла


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

Интерфейс приложения очень прост:

term_form.png; 2,73 kb
Рис 1. Форма будущей программы

Через поле ввода программа получает имя исполняемого файла (можно указать полное, сокращённое имя файла а так же опустить путь к файлу). По нажатию кнопки выполняется код поиска нужного процесса и его завершения. В программе я ориентируюсь на возможное применение UNICODE. Поэтому, задействованы макрос _TEXT() и тип TCHAR.

Код обработчика нажатия на кнопку:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCHAR buff[MAX_PATH];

HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hSnapshot == INVALID_HANDLE_VALUE) //-1
  {
  Application->MessageBox(_TEXT("Can't create snapshot of existing processes."),
				_TEXT("Error"), MB_ICONSTOP);
  return;
  }

PROCESSENTRY32 pe;
pe.dwSize = sizeof pe;
BOOL result = Process32First(hSnapshot, &pe);
while(result)
  {
  BOOL eq = lstrcmpi(pe.szExeFile, Edit1->Text.c_str());
  if(eq)
    {
    GetFileTitle(pe.szExeFile, buff, MAX_PATH);
    eq = lstrcmpi(buff, Edit1->Text.c_str());
    }
  if(eq)
    {
    GetShortPathName(pe.szExeFile, buff, MAX_PATH);
    eq = lstrcmpi(buff, Edit1->Text.c_str());
    }
  if(!eq)
    {
    CloseHandle(hSnapshot);
    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
    if(hProcess == NULL)
      {
      Application->MessageBox(_TEXT("Can't open process for termination."),
				_TEXT("Error"), MB_ICONSTOP);
      return;
      }
    if(TerminateProcess(hProcess, 0))
      {
      WaitForSingleObject(hProcess, INFINITE);
      CloseHandle(hProcess);
      Application->MessageBox(_TEXT("Process succesfully terminated."),
				_TEXT("Information"), MB_ICONINFORMATION);
      }
    return;
    }
  result = Process32Next(hSnapshot, &pe);
  }

CloseHandle(hSnapshot);
Application->MessageBox(_TEXT("Can't find process specified."), _TEXT("Error"), MB_ICONSTOP);
}

Код начинается с энумерации всех запущенных на данный момент процессов. Пользователи NT-платформ могут также задействовать функцию NtQuerySystemInformation (примечание: в Windows NT отсутствуют Toolhelp-функции).

Чтобы обеспечить условия, указанные в начале статьи (возможность указания полного, сокращённого и с опущенным путём имени файла), присутствует несколько операторов if, в которых производятся необходимые действия и, с помощью функции lstrcmpi (сравнение строк без учёта регистра), проверяется имя файла, из которого запущен текущий процесс в списке, на соответствие заданному.

Если соответствие найдено, производится попытка открыть процесс и завершить его. Для завершения процесса используется асинхронная функция TerminateProcess, поэтому мы дожидаемся завершения с помощью WaitForSingleObject.

Недостатки этого примера:

  • В приложениях подобного рода желательно пресекать попытки пользователя завершить саму эту программу, указав имя её исполняемого файла в поле ввода. Здесь это не предусмотрено. Если кто-то из читателей захочет добавить эту функцию, для получения имени исполняемого файла нашего приложения воспользуйтесь свойством ExeName объекта Application. Из API-функций здесь можно применить, например, GetCommandLine.
  • Пользователю не предоставляется возможность выбора, завершить ли все процессы, запущенные из указанного исполняемого файла (если такая ситуация присутствует), или же завершить только первый попавшийся (что и делает программа).
    Hosted by uCoz