The obvious question would be why you don't just use QueryFullProcessImageName, if that's what you want? Do you need compatibility with older versions of Windows?
The closest equivalent to QueryFullProcessImageName that's available on XP is probably GetModuleFileNameEx. I'd probably detect whether QueryFullProcessImageName is available and use it if possible, otherwise fall back to GetModuleFileNameEx.
Edit: While GetModuleFileNameEx isn't 100% dependable at retrieving the name of the executable for every possible process, it does work at least a fairly substantial part of the time. Here's a quick bit of test code I put together:
#include <windows.h>
#include <psapi.h>
#include <iostream>
#include <string>
#include <map>
std::string getfilename(DWORD pid) {
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
static int winver;
char path[256]= {0};
DWORD size = sizeof(path);
if (winver==0)
winver = GetVersion() & 0xf;
#if WINVER >= 0x600
if (winver >= 6)
QueryFullProcessImageName(process, 0, path, &size);
else
#endif
if (!GetModuleFileNameEx(process, NULL, path, sizeof(path)))
strcpy(path, "Unknown");
return std::string(path);
}
typedef std::map<DWORD, std::string> win_map;
namespace std {
ostream &operator<<(ostream &os, win_map::value_type const &v) {
return os << v.first << ": " << v.second;
}
}
BOOL CALLBACK show_info(HWND window, LPARAM lParam) {
win_map &exes = *(win_map *)lParam;
DWORD pid;
GetWindowThreadProcessId(window, &pid);
exes[pid] = getfilename(pid);
return true;
}
int main() {
win_map exes;
EnumWindows(show_info, (LPARAM)&exes);
std::copy(exes.begin(), exes.end(), std::ostream_iterator<win_map::value_type>(std::cout, "\n"));
return 0;
}
The results of a quick test are somewhat interesting. Compiled as 32-bit code, the version using QueryFullProcessImageName found 33 processes with top-level windows, and found names for 31 of those executables. The version using GetModuleFileNameEx, also found 33 processes, but only found names for 21 of the executable. If, however, I compile it as 64-bit code, either version finds filenames for 31 out of 33 executables (and the same two fail). Given the frequency with which you see XP/x64, that's probably of little consequence, but I found it interesting nonetheless.
In any case, even the least capable version (32-bit/GMFNE) found names for ~2/3rds of the files. While that's certainly not what you'd hope for, it's certainly better than nothing.