There are a bunch of different process listing APIs on Windows. They all have their plusses and minuses. However, I have never seen a summary of them, so I figured I would take a shot at it.
ntdll!NtQuerySystemInformation(SYSTEM_PROCESS_INFORMATION, …) - This is the internal, mostly undocumented NT API that should not be used directly. However, to my knowledge at least, all other APIs are built on top of this API, so I figured I would talk about it. The important features of this API are that it returns all of the processes, and it returns not just the process id, but also a fair amount of additional information. However, it does not return the full path to the executable (only the base name), and it does not return the user name.
psapi!EnumProcesses - This was one of the first public APIs for enumerating processes on NT-based OSs. This is a very thin wrapper on top of NtQuerySystemInformation. It does not hide processes, but it also only returns the process id. This is a problem if you also need the session id. There are APIs to return the session id from a process id, but they require access rights to open the process. Memory management can be a little challenging because the API does not provide a way to determine how many processes are actually running on the computer -- call the API in a loop and don't break until you provide a larger buffer than what is needed.
wtsapi32!WTSEnumerateProcesses – This is the process listing API provided by the Terminal Services team. This is the API to use if you want parody with task manager. As of Windows 2003, this is the only reasonable API that an administrator can use to determine the user name for every process on the computer. It also provides the session id and process basename information that NtQuerySystemInformation provides.
One gotcha with this API is that it restricts access to sessions that the calling user has access to. In some strange cases, this could be a problem. The strange case that one of my testers ran into was that if you log onto the console of a Server 2003 machine, and run a process list under a different user account (via runas), the process list will not include the process calling WTSEnumerateProcesses.
The other gotcha with this API is that it depends on the 'Terminal Services' service. This is not around on Win2k pro (ERROR_APP_WRONG_OS is returned). This could be disabled by the user (RPC_S_INVALID_BINDING is returned).
kernel32!CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) / kernel32!Process32First / kernel32!Process32Next - This is the Windows 95 process listing API that got ported to Windows 2000. I don't know this API as well, but I believe that this is also a thin wrapper on top of NtQuerySystemInformation. One interesting detail of this API is that on Windows 95/98/ME 'szExeFile' is the full path to the executable. On Windows 2000/XP/2003, 'szExeFile' is just the base name, which makes sense since NtQuerySystemInformation doesn't provide the full path. Lastly, this API also doesn't provide the session id, which is a problem if you need it.