Here’s how I would explain your code based on the structure, its parameters, use case, practical example, and exercise, similar to how you have done in your previous posts:


Code Explanation: Find and Terminate a Notepad Process

This code demonstrates how to use several key Windows APIs to locate a window by its title, retrieve the process ID for the window, open the process with appropriate access rights, and finally terminate the process.

We use the following Windows APIs:

  1. FindWindowA: Find a window handle by its name.
  2. GetWindowThreadProcessId: Retrieve the thread ID and process ID associated with a window.
  3. OpenProcess: Open a handle to the process with required access rights.
  4. TerminateProcess: Terminate a process using its handle.

API Breakdown

1. FindWindowA

Structure: This function searches for a window by its class name or window title. In our case, we use the window title.

Parameters:

  • classname: In this case, we are passing None because we are only searching by the window title.
  • windowname: The name of the window we are trying to find (e.g., “test2.txt - Notepad”).

Usage Scenario: Use this API to locate a window when you know its title or class name.

unsafe fn find_window (windowname: PCSTR) -> Result<HWND,windows::core::Error> {
    let window_handle = FindWindowA(None, windowname);
    match window_handle.0 {
        0 => {
            let error_code = GetLastError();
            Err(error_code.into())
        },
        _ => Ok(window_handle),
    }
}

Explanation:

  • The code looks for the window with the title windowname.
  • If a window is found, the function returns its handle (HWND); otherwise, it retrieves the error code with GetLastError().

2. GetWindowThreadProcessId

Structure: This function retrieves the thread ID and process ID of the window found in the previous step.

Parameters:

  • hwnd: The window handle found by FindWindowA.
  • lpdwprocessid: This parameter stores the process ID.

Usage Scenario: Use this when you have a window handle and want to know the process or thread associated with it.

unsafe fn get_window_thread_process_id (hwnd: HWND) -> Result<u32, windows::core::Error> {
    let mut process_id = 0;
    let thread_id = GetWindowThreadProcessId(hwnd, Some(&mut process_id as *mut u32));
    match thread_id {
        0 =>  {
            let error_code = GetLastError();
            Err(error_code.into())
        },
        _ => Ok(process_id)
    }
}

Explanation:

  • This function extracts the process ID of the window.
  • It returns the process ID or an error if it cannot retrieve the information.

3. OpenProcess

Structure: This function opens the process associated with the process ID returned by the previous function, allowing us to perform actions such as termination.

Parameters:

  • dwdesiredaccess: The access rights we need. In this case, we request PROCESS_ALL_ACCESS.
  • binherithandle: Determines whether the handle is inheritable (we set it to false).
  • process_id: The process ID we want to open.

Usage Scenario: Use this function to obtain a handle to the process, allowing further actions like termination.

unsafe fn open_process (process_id: u32) -> Result<HANDLE, windows::core::Error> {
    let dwdesiredaccess: PROCESS_ACCESS_RIGHTS = PROCESS_ALL_ACCESS;
    let binherithandle = false;
    let process_handle = OpenProcess(dwdesiredaccess, binherithandle, process_id)?;
    Ok(process_handle)
}

Explanation:

  • This function opens the process with PROCESS_ALL_ACCESS rights, allowing us to perform any operation on the process, including termination.
  • If successful, it returns a process handle (HANDLE).

4. TerminateProcess

Structure: This function terminates the process using its handle.

Parameters:

  • process_handle: The handle to the process obtained via OpenProcess.
  • lpexitcode: The exit code to be returned by the process.

Usage Scenario: Use this when you need to terminate a process.

unsafe fn terminate_process (process_handle: HANDLE) -> Result<(), windows::core::Error> {
    let lpexitcode: u32 = 1;
    let process = TerminateProcess(process_handle, lpexitcode)?;
    Ok(process)
}

Explanation:

  • This function terminates the process by providing the process handle and an exit code.

Example Workflow

Here’s how the code functions together:

  1. Find the window with the title "test2.txt - Notepad".
  2. Get the process ID associated with the window.
  3. Open the process with the process ID, allowing access to terminate it.
  4. Terminate the process with an exit code of 1.

Complete Code Explanation

fn main() -> Result<(), windows::core::Error> {
    // Define the window title to find (in this case, a Notepad file)
    let windowname: PCSTR = s!("test2.txt - Notepad");
 
    // Step 1: Find the window handle
    let window_handle = unsafe { find_window(windowname)? };
    println!("The window handle is: {:?}", window_handle);
 
    // Step 2: Retrieve the process ID associated with the window
    let process_id = unsafe { get_window_thread_process_id(window_handle)? };
    println!("The process ID is: {:?}", process_id);
 
    // Step 3: Open the process to get a handle
    let process_handle = unsafe { open_process(process_id)? };
    println!("The process handle is: {:?}", process_handle);
 
    // Step 4: Terminate the process
    let close_process = unsafe { terminate_process(process_handle)? };
 
    Ok(())
}

Exercise

Goal: Modify the code to search for a different window, such as “Calculator,” and then terminate the process associated with it.

Steps:

  1. Change the windowname to match the title of another running application.
  2. Follow the same process to terminate that application.

Full Project Challenge

Challenge: Create a complete project that automates the termination of a process based on user input for the window title. The program should:

  • Prompt the user for the window title.
  • Find the window, retrieve the process ID, and terminate the process.

By breaking down the code and providing exercises, this explanation follows the approach used in your previous posts, guiding readers through each step of the process while encouraging hands-on practice.