HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Using ::CreateToolhelp32Snapshot

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
createtoolhelp32snapshotusingstackoverflow

Problem

I have a process, let's call it Proc1. It is installed in two different directories and one instance of each is running:

  • C:\DirA\Proc1.exe



  • C:\DirB\Proc1.exe



When iterating through all currently running processes, I need to be able to differentiate one from the other. I do this by looking at the full path to the process.

Unfortunately, a little piece of documentation from MSDN has forced me to make this code pretty ugly:

MSDN


If the function fails with ERROR_BAD_LENGTH when called with TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32, call the function again until it succeeds.

Please assume that C++11 is not available for this project.

bool MyClass::IsCorrectPath (const DWORD dwPid, const std::string &strPath) const
{
    DWORD dwError = 0 ;
    NormalHandle hModSnap ; // RAII wrapper for HANDLE

    do {
        hModSnap = ::CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, dwPid) ;
        if (hModSnap == INVALID_HANDLE_VALUE) {
            dwError == ::GetLastError () ;
            if (dwError == ERROR_PARTIAL_COPY) {
                // This occurs when trying to read a 64 bit process from a 32 bit process.
                return false ;
            }

            else if (dwError == ERROR_BAD_LENGTH) {
                // We have to repeatedly call ::CreateToolhelp32Snapshot () if we get this error
                continue ;
            }

            else {
                ThrowFunctionFailure ("MyClass::IsCorrectPath ()", 
                    "::CreateToolhelp32Snapshot ()", ::GetLastError ()) ;
            }
        }       

    } while ((hModSnap == INVALID_HANDLE_VALUE) && (dwError == ERROR_BAD_LENGTH)) ;

    MODULEENTRY32 me ;
    me.dwSize = sizeof (me) ;
    if (::Module32First (hModSnap.Get (), &me) == FALSE) {
        ThrowFunctionFailure ("MyClass::IsCorrectPath ()", "::Module32First ()", ::GetLastError ()) ;
    }

    return (::_stricmp (strPath.data (), me.szExePath) == 0) ;
}

Solution

I think you don't need to check for errors twice, and that will make your code cleaner.

bool MyClass::IsCorrectPath (const DWORD dwPid, const std::string &strPath) const
{
    DWORD dwError = 0 ;
    NormalHandle hModSnap ; // RAII wrapper for HANDLE
    ::SetLastError (0) ;

    do {   
        // repeat while the expected error occurs
        hModSnap = ::CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, dwPid) ;
        dwError == ::GetLastError () ;
    } while ((hModSnap == INVALID_HANDLE_VALUE) && (dwError == ERROR_BAD_LENGTH)) ;

    if (dwError == ERROR_PARTIAL_COPY) {
         // This occurs when trying to read a 64 bit process from a 32 bit process.
         return false ;
    }

    if (hModSnap == INVALID_HANDLE_VALUE) {
        ThrowFunctionFailure ("MyClass::IsCorrectPath ()", 
            "::CreateToolhelp32Snapshot ()", ::GetLastError ()) ;
    }

    MODULEENTRY32 me ;
    me.dwSize = sizeof (me) ;
    if (::Module32First (hModSnap.Get (), &me) == FALSE) {
        ThrowFunctionFailure ("MyClass::IsCorrectPath ()", "::Module32First ()", ::GetLastError ()) ;
    }

    return (::_stricmp (strPath.data (), me.szExePath) == 0) ;
}


So, instead of checking for all errors in every step of the loop, only check for the expected error.

Once you're out of the loop, it means you received a different error or you have a valid handle. Check if success and continue.

Does that make sense to you?

edit: Changed dwError == ERROR_SUCCESS to dModSnap == INVALID_HANDLE_VALUE.

Code Snippets

bool MyClass::IsCorrectPath (const DWORD dwPid, const std::string &strPath) const
{
    DWORD dwError = 0 ;
    NormalHandle hModSnap ; // RAII wrapper for HANDLE
    ::SetLastError (0) ;

    do {   
        // repeat while the expected error occurs
        hModSnap = ::CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, dwPid) ;
        dwError == ::GetLastError () ;
    } while ((hModSnap == INVALID_HANDLE_VALUE) && (dwError == ERROR_BAD_LENGTH)) ;

    if (dwError == ERROR_PARTIAL_COPY) {
         // This occurs when trying to read a 64 bit process from a 32 bit process.
         return false ;
    }

    if (hModSnap == INVALID_HANDLE_VALUE) {
        ThrowFunctionFailure ("MyClass::IsCorrectPath ()", 
            "::CreateToolhelp32Snapshot ()", ::GetLastError ()) ;
    }

    MODULEENTRY32 me ;
    me.dwSize = sizeof (me) ;
    if (::Module32First (hModSnap.Get (), &me) == FALSE) {
        ThrowFunctionFailure ("MyClass::IsCorrectPath ()", "::Module32First ()", ::GetLastError ()) ;
    }

    return (::_stricmp (strPath.data (), me.szExePath) == 0) ;
}

Context

StackExchange Code Review Q#38839, answer score: 2

Revisions (0)

No revisions yet.