-2

I'm cycling through a process snapshot of TlHelp32 and then comparing the names with stricmp to get the process handle. The problem is even though both values seem to be the same, they apparently are not since it doesn't return 0 . I don't know why though, I have tried writing the process name into the function as well.

HANDLE GetProcessValues(std::string ProcName)
{
   const char* ProcNameChar = ProcName.c_str();
   HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   PROCESSENTRY32 process;
   ZeroMemory(&process, sizeof(process));
   process.dwSize = sizeof(process);
   if (Process32First(snapshot, &process))
   {
       do
       {
           if (_stricmp((char*)process.szExeFile,ProcNameChar)==0)
           {
               HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
               return hProc;
           }
       }while (Process32Next(snapshot,&process));
   }
   return 0;
}

I debugged it to see if the values fit: Screenshot

Orca
  • 108
  • 7
  • 1
    From your image `process.szExeFile` is a wchar* not char*. – drescherjm Dec 13 '16 at 22:01
  • 6
    Why did you cast to `char *` in the first argument of `_stricmp`? If it was to shut the compiler up about a type mismatch error, stop doing that and provide the correct string type to the function. Never cast string types -- casting is **not** conversion. – PaulMcKenzie Dec 13 '16 at 22:02
  • 5
    You lied to the compiler and got your just desserts – David Heffernan Dec 13 '16 at 22:05
  • Also, the debugger is smart enough to show you the readable text. What that process.szExeFile actually is is a double byte character string. Remember the debugger only is an aide in making the data look "nice" in the debug window. If you really wanted to see what the string looks like, go to the memory window and look at that string. You see that it has holes (`\0` characters) in it between bytes. – PaulMcKenzie Dec 13 '16 at 22:08
  • Hm the \0 are at the end of the Wchar, I expected the function to stop comparing when one of the strings ends, my bad. Another question though, the ProcNameChar has the value "java.exe" but when I expand it it only contains "j", if anyone could ellaborate that I would be very happy, I'm asking if that could later on also cause problems while comparing. Thanks to most of you. – Orca Dec 13 '16 at 22:18
  • The reason why it expands to only 'J' is more than likely you tried to stick a 16-bit character string into an 8-bit character string type, and you're using ANSI functions to view the string. Your string is probably `J\0v\0a\0.\0e\0x\0e` . You need to seriously go over your entire app and decide what character set your strings use and use that character set consistently, and not mix them up and get away from all the errors by casting. – PaulMcKenzie Dec 13 '16 at 22:21
  • And no, the wide string does not just end with '\0'. In your case, it more than likelyt has null bytes interspersed between the characters. You can only see that when you look at a *memory* dump of the string, not a "debugger view" of the string. – PaulMcKenzie Dec 13 '16 at 22:24
  • Ah yes I'm seeing it now, but just in theory could I wipe every 2nd char and then compare the strings if the length matches? – Orca Dec 13 '16 at 22:29
  • 3
    Instead of hacks, make your application Unicode. and use `std::wstring` instead of `std::string`, `wchar_t` instead of `char`, etc. – PaulMcKenzie Dec 13 '16 at 22:32
  • 2
    You need to get your head round the fact that you have to stop lying to the compiler. That is step 1. – David Heffernan Dec 13 '16 at 22:33
  • I thought the problem was the WCHAR not the string? Isn't a string basically what the function expects and the problem was me stupidly casting the WCHAR to a char*? The string in memory was fine (according to me). – Orca Dec 13 '16 at 22:36
  • 2
    The problem is that you've got a hodgepodge of string types, and you don't have a coherent design as to what the actual string type that your application is using. Char here, wchar there, Unicode function calls here, ANSI function calls there, etc. Focus on using one and only one string type, and call the correct functions that deal with those string types. Preferably stick to Unicode, since there are very few MBCS applications being currently created in this day and age of Windows. – PaulMcKenzie Dec 13 '16 at 23:41

2 Answers2

2

The problem is that you are using the TCHAR versions of Process32First()/Process32Next(), and your debugger screnshot clearly shows that you are compiling your project for Unicode, so TCHAR maps to WCHAR and thus process.szExeFile is a WCHAR[] array. You are incorrectly type-casting that array to a char* pointer. You cannot directly compare a Unicode string to an Ansi string. You need to convert one string to the encoding of the other string before then comparing them.

You are also leaking the HANDLE returned by CreateToolhelp32Snapshot().

Since you are passing an Ansi std::string as input to your GetProcessValues() function, the easiest solution would be to use the Ansi versions of Process32First()/Process32Next() instead, so process.szExeFile is now a CHAR[] array, and thus no conversion is needed:

HANDLE GetProcessValues(std::string ProcName)
{
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE)
        return NULL;

    PROCESSENTRY32A process;
    ZeroMemory(&process, sizeof(process));
    process.dwSize = sizeof(process);

    const char* ProcNameChar = ProcName.c_str();
    HANDLE hProc = NULL;

    if (Process32FirstA(snapshot, &process))
    {
        do
        {
            if (_stricmp(process.szExeFile, ProcNameChar) == 0)
            {
                hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
                break;
            }
        }
        while (Process32NextA(snapshot, &process));
    }

    CloseHandle(snapshot);
    return hProc;
}

However, you really should stay away from using Ansi APIs. Windows is a Unicode-based OS, and has been for a long time. Use Unicode APIs instead:

HANDLE GetProcessValues(std::wstring ProcName)
{
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE)
        return NULL;

    PROCESSENTRY32W process;
    ZeroMemory(&process, sizeof(process));
    process.dwSize = sizeof(process);

    const wchar_t* ProcNameChar = ProcName.c_str();
    HANDLE hProc = NULL;

    if (Process32FirstW(snapshot, &process))
    {
        do
        {
            if (_wcsicmp(process.szExeFile, ProcNameChar) == 0)
            {
                hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
                break;
            }
        }
        while (Process32NextW(snapshot, &process));
    }

    CloseHandle(snapshot);
    return hProc;
}

If your ProcName parameter absolutely must be a std::string, then you can either:

  1. convert ProcName to Unicode using MultiByteToWideChar(), std::wstring_convert, etc, and then compare that result to the strings returned by the Unicode API.

  2. convert strings from the Unicode API to Ansi using WideCharToMultiByte(), std::wstring_convert, etc, and then compare those results to ProcName.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

when dealing with wchar* data type, use _wcsicmp for comparison, and - if necessary - convert any involved char* data type into a wchar*-equivalent, e.g. using CStringW class. Confer microsoft _wcsicmp, and be also aware of using a correct locale. A similar problem, yet with wchar* constants, has been described at stack overflow

Community
  • 1
  • 1
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • `wchar*` is not an integral data type in C++. You are confusing this with C++'s `wchar_t*`, or the Windows SDK's `WCHAR*`. Besides that, `CStringW` is (presumably) an MFC/ATL class template. Unless you are writing MFC or ATL code, this isn't applicable (it generally isn't for Windows API programming). The conversion function in the Windows API is [MultiByteToWideChar](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx). A C++ alternative would be [std::mbstowcs](http://en.cppreference.com/w/cpp/string/multibyte/mbstowcs). – IInspectable Dec 14 '16 at 19:42