// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993, 1994  Microsoft Corporation.  All Rights Reserved.
//
//  MODULE:   procthrd.c
//
//  PURPOSE:  Implements process and thread enumeration/manipulation
//            functions. 
//
//  FUNCTIONS:
//    RefreshThreadList     - Enumerates and displays active threads
//    RefreshProcessList    - Enumerates and displays active processes
//    GetProcessModule      - Gets information about a specific module in 
//                            a specified process
//    KillProcess           - Kills the specified process
//
//  COMMENTS:
//


#include <windows.h>
#include <tlhelp32.h>          // Required for ToolHelp32 functions
#include <commctrl.h>
#include "procthrd.h"
#include "listview.h"
#include "globals.h"


//-------------------------------------------------------------------------
// Local function prototypes.

BOOL GetProcessModule (DWORD dwPID, DWORD dwModuleID, LPMODULEENTRY32 lpMe32,
                       DWORD cbMe32);

//
//  FUNCTION: RefreshThreadList(HWND, DWORD)
//
//  PURPOSE:  Enumerates and displays the list of threads owned by a 
//            specified process.
//
//  PARAMETERS:
//    hListView    - Handle of the listview that lists thread information
//    dwOwnerPID   - ID of process whose threads we will list
//
//  RETURN VALUE:
//    TRUE if the threads were successfully enumerated and listed
//	  FALSE if the threads could not be enumerated or listed
//
//  COMMENTS:
//

BOOL RefreshThreadList (HWND hListView, DWORD dwOwnerPID)
{
    HANDLE        hThreadSnap = NULL;
    BOOL          bRet        = FALSE;
    THREADENTRY32 te32        = {0};

    // Take a snapshot of all threads currently in the system.
    hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (hThreadSnap == (HANDLE)-1)
       return (FALSE);

    // Clear the current contents of the thread list view (which are now old).
    ListView_DeleteAllItems(g_hwndThread);

    // Size of the THREADENTRY32 structure must be filled out before use.
    te32.dwSize = sizeof(THREADENTRY32);

    // Walk thread snapshot to find all threads of the process we want.
    // If the thread belongs to the process we want, add its information  
    // to the display list.
    if (Thread32First(hThreadSnap, &te32))
	{
		do 
		{   
		    if (te32.th32OwnerProcessID == dwOwnerPID)
		    {   
		        TINFO ti;
                              
		        ti.tid       = te32.th32ThreadID;
		        ti.pidOwner  = te32.th32OwnerProcessID;
			    ti.tpBasePri = te32.tpBasePri;

			    AddThreadItem(hListView, ti);
		    }
		}
		while (Thread32Next(hThreadSnap, &te32));
		bRet = TRUE;
	}
    else
        bRet = FALSE;          // Couldn't walk the list of threads.

    // Don't forget to clean up the snapshot object...
    CloseHandle (hThreadSnap);

    return (bRet);
}


//
//  FUNCTION: RefreshProcessList(HWND)
//
//  PURPOSE:  Enumerates and displays the list of processes.
//
//  PARAMETERS:
//    hListView   - Handle of the listview that lists process information
//
//  RETURN VALUE:
//    TRUE if the processes were successfully enumerated and listed
//	  FALSE if the processes could not be enumerated or listed
//
//  COMMENTS:
//	  Refreshes the list of processes by making a process snapshot and
//    putting info about each process into the listview control specifed by
//    hListView.

BOOL RefreshProcessList (HWND hListView)
{
    HANDLE         hProcessSnap = NULL;
    BOOL           bRet         = FALSE;
    PROCESSENTRY32 pe32         = {0};

    // Take a snapshot of all processes currently in the system.
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == (HANDLE)-1)
       return (FALSE);

    // Clear the current contents of the process list view (which are now old).
    ListView_DeleteAllItems(g_hwndProcess);

    // Size of the PROCESSENTRY32 structure must be filled out before use.
    pe32.dwSize = sizeof(PROCESSENTRY32);

    // Walk the snapshot of processes and for each process, get information
    // to display.
    if (Process32First(hProcessSnap, &pe32))
    {
        BOOL          bGotModule = FALSE;
        MODULEENTRY32 me32       = {0};
        PINFO         pi         = {0};

        do 
        {
            bGotModule = GetProcessModule(pe32.th32ProcessID, 
                                          pe32.th32ModuleID, 
                                          &me32, 
                                          sizeof(MODULEENTRY32));
            if (bGotModule)
            {
                pi.pid            = pe32.th32ProcessID;
                pi.pcPriClassBase = pe32.pcPriClassBase;
                pi.cntThreads     = pe32.cntThreads;
                lstrcpy(pi.szModName, me32.szModule);
				lstrcpy(pi.szFullPath, me32.szExePath);

                AddProcessItem(hListView, pi);
            }
        }
        while (Process32Next(hProcessSnap, &pe32));
        bRet = TRUE;
    }
    else
        bRet = FALSE;    // Couldn't walk the list of processes.

    // Don't forget to clean up the snapshot object...
    CloseHandle (hProcessSnap);
    return (bRet);
}



//
//  FUNCTION: GetProcessModule(DWORD, DWORD, LPMODULEENTRY32, DWORD)
//
//  PURPOSE:  Given a Process ID and module ID, return its module information.
//
//  PARAMETERS:
//    dwPID      - ID of process that owns the module we want information 
//                 about.
//    dwModuleID - ToolHelp32 ID of the module within the process
//    lpMe32     - Structure to return data about the module we want
//    cbMe32     - Size of the buffer pointed to by lpMe32--to make sure we 
//                 don't copy too much data into lpMe32.
//
//  RETURN VALUE:
//    TRUE if it returns information about the specifed module.
//    FALSE if it could not enumerate the modules in the process, or the
//          module is not found in the process.
//
//  COMMENTS:
//

BOOL GetProcessModule (DWORD           dwPID, 
					   DWORD           dwModuleID, 
					   LPMODULEENTRY32 lpMe32, 
                       DWORD           cbMe32)
{   
    BOOL          bRet        = FALSE;
    BOOL          bFound      = FALSE;
    HANDLE        hModuleSnap = NULL;
    MODULEENTRY32 me32        = {0};

    // Take a snapshot of all modules in the specified process.
    hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
    if (hModuleSnap == (HANDLE)-1)
       return (FALSE);

    // Size of the MODULEENTRY32 structure must be initialized before use!
    me32.dwSize = sizeof(MODULEENTRY32);

    // Walk the module list of the process and find the module we are 
    // interested in.  Then, copy the information to the buffer pointed to
    // by lpMe32 so that we can return it to the caller.
    if (Module32First(hModuleSnap, &me32))
    {
        do 
        {
            if (me32.th32ModuleID == dwModuleID)
            {
                CopyMemory (lpMe32, &me32, cbMe32);
                bFound = TRUE;
            }
        }
        while (!bFound && Module32Next(hModuleSnap, &me32));

        bRet = bFound;   // If this sets bRet to FALSE, then dwModuleID 
                         // no longer exsists in the specified process.
    }
    else
        bRet = FALSE;           // Couldn't walk module list.

    // Don't forget to clean up the snapshot object...
    CloseHandle (hModuleSnap);

    return (bRet);
}


//
//  FUNCTION: KillProcess(DWORD)
//
//  PURPOSE:  To kills a specified process
//
//  PARAMETERS:
//    dwPID      - Process ID of the process to kill
//
//  RETURN VALUE:
//    TRUE if the specified process was killed
//    FALSE if it wasn't killed.
//
//  COMMENTS:
//    KillProcess does not return until the process is terminated.
//

BOOL KillProcess (DWORD dwPID)
{
    BOOL   bRet     = FALSE;
    HANDLE hProcess = NULL;

    // Open the process to obtain a handle to it.  If we get a handle,
    // try to terminate the process.  Wait until the process is really
	// dead before returning.
    hProcess = OpenProcess (PROCESS_TERMINATE, FALSE, dwPID);
    if (hProcess != NULL)
    {    
        bRet = TerminateProcess (hProcess, 0xFFFFFFFF);
        WaitForSingleObject(hProcess, INFINITE);
        CloseHandle (hProcess);
    }
    else
        bRet = FALSE;

    return (bRet);
}
