views:

21

answers:

2

Hi,

I needed to enumerate running processes and wondered for a while why my code wasn't working:

PROCESSENTRY32 ProcEntry;
ZeroMemory (&ProcEntry, sizeof (PROCESSENTRY32)); //problem
ProcEntry.dwFlags = sizeof(PROCESSENTRY32);

HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

if (Snapshot == INVALID_HANDLE_VALUE)
    return false;

if (Process32First(Snapshot, &ProcEntry))
    ....

Problem was that Process32First always returned FALSE because of ERROR_BAD_LENGTH error.

Once I removed ZeroMemory line, everything started working fine. So the question is, why ZeroMemory caused it? It should just fill memory at the address of X for Z bytes. I use it a lot for winapi pointer-like structures, this time I didnt realise its a local variable but that doesn't explain the problem or does it?

Thanks,

Kra

EDIT: plus I found out code works fine only in Debug version, once I compile it as Release version, its bugged again :/

A: 

You cannot zero out the entire PROCESSENTRY32 structure as it is self-describing - you have to set dwSize. From the sample here:

  HANDLE hProcessSnap;
  HANDLE hProcess;
  PROCESSENTRY32 pe32;
  DWORD dwPriorityClass;

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

  // Set the size of the structure before using it.
  pe32.dwSize = sizeof( PROCESSENTRY32 );

  // Retrieve information about the first process,
  // and exit if unsuccessful
  if( !Process32First( hProcessSnap, &pe32 ) )
  {
    printError( TEXT("Process32First") ); // show cause of failure
    CloseHandle( hProcessSnap );          // clean the snapshot object
    return( FALSE );
  }
Steve Townsend
@sharptooth - OP's code does not set `dwSize`, hence it's passed to the Win32 API as 0, hence Win32 error code 'bad length' that OP noted. If `dwSize` is not set at all (when there is no `ZeroMemory`) then struct has floating `dwSize` which may or may not work.
Steve Townsend
Hell yeah, I know its size must be set. I have no idea why i set flags value instead of size (I guess some autocomplete feature and badly chosen option). That of course did the trick. So can I assume ZeroMemory can be safely used on local variables?
Kra
@Steve Townsend: I got it. I spend a minute staring at the code before I realized he set the wrong member variable.
sharptooth
@Kra - yes, that's fine so long as you set the fields that are required. Curse that Intellisense autocomplete, right?
Steve Townsend
@Kra: Yes, you can use `ZeroMemory()` as well as `memset()` - see this related question: http://stackoverflow.com/questions/1998752/which-one-to-use-memset-or-value-initialization-to-zero-out-a-struct
sharptooth
Steve: yep, I like Intellisense but its not idiot-proof, right? :))sharptooth: I debugged it for over an hour trying to figure out what the hell is going on .. I wish it would take me a minute .. :)
Kra
@Kra - don't be too hard on yourself. These native APIs are a pain to get right...
Steve Townsend
@Kra: This happens once in a while, don't pay too much attention to it.
sharptooth
A: 

You should set dwSize, not dwFlags.

ProcEntry.dwFlags = sizeof(PROCESSENTRY32);

should be

ProcEntry.dwSize = sizeof(PROCESSENTRY32);
sharptooth