Michael Haephrati Ответов: 3

Мониторинг текущего состояния процесса


Я попытался написать небольшое POC (Win32-приложение), которое будет вызывать "calc.exe" используя CreateProcess() и периодически получая статус (он все еще работает или был закрыт) с помощью GetExitCodeProcess().

Мой код "быстрый и грязный" только для того, чтобы узнать, как использовать GetExitCodeProcess (), или должен ли я использовать другой метод, или, может быть, calc.exe это не идеальный процесс для такого POC. Тем не менее, мне нужно использовать CMD, и я ищу решение, которое позволит мне контролировать процесс, который инкапсулирует CMD в нем, как в моем статья об этом[^] который я надеюсь улучшить.

Я ожидал получить другой статус, когда отключусь calc.exe но я всегда получаю статус 0.

Что я уже пробовал:

// MonitorProcess.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "MonitorProcess.h"

#define MAX_LOADSTRING 100

#define BUFSIZE MAX_PATH
#define IDT_TIMER1 1000

PROCESS_INFORMATION pi;

BOOL DoRun(WCHAR *command)
{
	BOOL Result = FALSE;
	DWORD retSize;
	LPTSTR pTemp = NULL;
	TCHAR Command[BUFSIZE] = L"";
	_tcscpy_s(Command, L"C:\\Windows\\system32\\cmd.exe /C ");
	_tcscat_s(Command, command);

	STARTUPINFO si;
	SecureZeroMemory(&si, sizeof(STARTUPINFO));

	si.cb = sizeof(STARTUPINFO);

	Result = CreateProcess(
		NULL,
		Command,
		NULL,
		NULL,
		FALSE,
		CREATE_NO_WINDOW,
		NULL,
		NULL,
		&si,
		&pi);

	if (Result == FALSE)
	{
		retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_ARGUMENT_ARRAY,
			NULL,
			GetLastError(),
			LANG_NEUTRAL,
			(LPTSTR)&pTemp,
			0,
			NULL);
		MessageBox(NULL, pTemp, L"Error", MB_OK);
		if (retSize)
		{
			LocalFree(pTemp);
		}
	}
	return Result;
}

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_MONITORPROCESS, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
	hInst = hInstance; // Store instance handle in our global variable

	HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

	if (!hWnd)
	{
		return FALSE;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);


	DoRun((WCHAR *)L"calc.exe");
	SetTimer(hWnd,             // handle to main window 
		IDT_TIMER1,            // timer identifier 
		10000,                 // 10-second interval 
		(TIMERPROC)NULL);     // no timer callback 
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MONITORPROCESS));

    MSG msg;
	DWORD state;


    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
	// note: this is the hProcess returned from OpenProcess


    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MONITORPROCESS));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_MONITORPROCESS);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}


//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	DWORD exitCode = 0;
	BOOL success = FALSE;
    switch (message)
    {
		case WM_TIMER:
		{
			switch (wParam)
			{
			case IDT_TIMER1:
				success = GetExitCodeProcess(pi.hProcess, &exitCode);
				break;
			default:
				break;
			}
		}
		wchar_t Message[80];
		swprintf(Message,80,L"Exit code = %d success = %d", exitCode, success);
		MessageBox(NULL, Message, L"", MB_OK);
		break;

		case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
		
		case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
		
		case WM_DESTROY:
        PostQuitMessage(0);
        break;
		
		default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

3 Ответов

Рейтинг:
28

Jim Forst

Если вы попробуете другую команду, вызываемую CDM, особенно такую, которая требует времени, например ipconfig, она может сработать.

Когда ты бежишь calc.exe это как печатать на машинке

start calc.exe

в CMD и calc.exe это не тот процесс, который вы начинаете с CreateProcess()


Michael Haephrati

Я согласен, что когда внешняя программа, как calc.exe запускается CMD, нам нужно внешне найти идентификатор процесса нового процесса (calc.exe) и следить за ним

Рейтинг:
2

KarstenK

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


Michael Haephrati

Не могли бы вы уточнить? Связанный пример не поможет до тех пор, пока я хочу периодически проверять состояние процесса

Рейтинг:
0

Rick York

Похоже, что cmd запущен, так что вы действительно получаете его код выхода. Если вы хотите проверить, как вы получаете код выхода из процесса, вам, вероятно, следует создать собственный пользовательский процесс, который будет возвращать любой код выхода, который вы хотите, чтобы он возвращал. Вы могли бы попросить его ввести код выхода, если бы захотели.

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


Michael Haephrati

На самом деле мне нужно отслеживать процесс, который был вызван CMD. Должен быть способ сделать это. WaitForSingleObject потребует отдельного потока, иначе я не смогу периодически проверять состояние, как сейчас, с помощью события WM_TIMER.

Rick York

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

Я бы написал пользовательский процесс, чтобы проверить это, потому что я не знаю, передает ли cmd обратно код выхода процесса, который он запускает, или нет.

Действительно ли этот процесс должен быть запущен с помощью cmd? Вы не можете просто создать свою собственную консоль и запустить процесс на ней?

[no name]

Если вы попробуете другую команду, вызываемую CDM, особенно ту, которая требует времени, например "ipconfig", она может сработать. Когда ты бежишь calc.exe это как набирать " старт calc.exe’ в CMD и calc.exe это не тот процесс, который вы начинаете с CreateProcess