7

I'm trying to get a process ID by a process name (for example, notepad.exe), but previous solutions on Stack Overflow don't seem to work properly. Here is what I've tried:

DWORD FindProcessId(const char *processname)
{
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    DWORD result = NULL;

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

    // Retrieve information about the first process,
    // and exit if unsuccessful
    if (!Process32First(hProcessSnap, &pe32))
    {
        CloseHandle(hProcessSnap);          // Clean the snapshot object
        return(FALSE);
    }

    do
    {
        if (0 == _stricmp(processname, pe32.szExeFile))
        {
            result = pe32.th32ProcessID;
            break;
        }
    } while (Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);

    return result;
}

I pass in "notepad.exe" and confirm that it is running on my system, and that the application is running as Administrator with the correct privileges required. Elevation is done like this:

        if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
        {
            // Launch itself as administrator.
            sei.lpVerb = TEXT("runas");
            sei.lpFile = szPath;
            sei.hwnd = NULL;
            sei.nShow = SW_NORMAL;

            if (!ShellExecuteEx(&sei))
            {
                MessageBox(NULL, TEXT("The program needs to be elevated to work properly."), APP_TITLE, MB_OK);
                return -1;
            }
        }
        return 0;

It never finds the process ID - returns Null every time.

This is using C, not C++.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christian Stewart
  • 15,217
  • 20
  • 82
  • 139

1 Answers1

8

The solution is to simply set the pe32.dwSize after getting the process snapshot. Complete fixed code here:

DWORD FindProcessId(const char *processname)
{
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    DWORD result = 0;

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

    pe32.dwSize = sizeof(PROCESSENTRY32); // <----- IMPORTANT

    // Retrieve information about the first process,
    // and exit if unsuccessful
    if (!Process32First(hProcessSnap, &pe32))
    {
        CloseHandle(hProcessSnap);          // clean the snapshot object
        printf("!!! Failed to gather information on system processes! \n");
        return(0);
    }

    do
    {
        printf("Checking process %ls\n", pe32.szExeFile);
        if (0 == strcmp(processname, pe32.szExeFile))
        {
            result = pe32.th32ProcessID;
            break;
        }
    } while (Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);

    return result;
}
Christian Stewart
  • 15,217
  • 20
  • 82
  • 139
  • Also, if you are interested, I have a code for this using only `NtQuerySystemInformation`. I think it's more elegant alternative to the sloppy toolhelp32 functions. But I'd understand if you didn't want to link against ntdll. – user2345215 Jan 01 '14 at 23:42
  • @user2345215 If you have an implementation please share! – Christian Stewart Jan 01 '14 at 23:53
  • 1
    Well, it's actually in c++, not c, so I'll just post a pastebin link here: http://pastebin.com/LNf4XHJs – user2345215 Jan 02 '14 at 00:32
  • Anyway, I cut it down a little bit. It was a little bit bigger than I imagined and I didn't want to introduce too many internal structures. But `ImageName` is not really a plain `WCHAR` there, it's a `UNICODE_STRING`, there are two USHORT values just before the `ImageName` and the first of them is the length of the string. It's probably null terminated, but I wouldn't rely on that. It's probably not worth it to do all this unless you want some other info in that structure that's not normally available. (and I hid it all under `unused`) – user2345215 Jan 02 '14 at 00:45
  • 1
    Thank you for posting your answer. It is a very useful function. (+1). Id like to offer 2 suggestions though, initializing a `DWORD` to `NULL` throws a warning. Changing `DWORD result = NULL;` to: `DWORD result = 0;` suppresses the warning. It follows that the line: `return(NULL);` should be: `return(0);` – ryyker Dec 13 '17 at 14:42