32bit プロセスは 64bit プロセスを見つけられない

所用で「あるプロセスから別のプロセスを終了させるプログラム」を書いていました.終了させる部分の関数は以下のような感じ.

#include <string>
#include <vector>
#include <windows.h>
#include <tchar.h>
#include <psapi.h>

#pragma comment(lib, "psapi.lib")

namespace process {
    std::size_t kill(const std::basic_string<TCHAR>& name) {
        std::size_t result = 0;
        
        std::vector<DWORD> processes(256, 0);
        DWORD procbytes = 0;
        while (1) {
            if (!::EnumProcesses(reinterpret_cast<DWORD*>(&processes[0]), processes.size() * sizeof(DWORD), &procbytes)) return 0;
            if (procbytes < processes.size() * sizeof(DWORD)) break;
            processes.resize(processes.size() * 2);
            procbytes = 0;
        }
        
        for (std::size_t i = 0; i < procbytes / sizeof(procbytes); ++i) {
            HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, processes[i]);
            if (!process) continue;
            
            std::vector<HMODULE> modules(256, 0);
            DWORD modulebytes = 0;
            BOOL status = TRUE;
            while (1) {
                status = ::EnumProcessModules(process, reinterpret_cast<HMODULE*>(&modules[0]), modules.size() * sizeof(HMODULE), &modulebytes);
                if (!status || modulebytes < modules.size() * sizeof(HMODULE)) break;
                modules.resize(modules.size() * 2);
                modulebytes = 0;
            }
            
            if (status) {
                for (std::size_t j = 0; j < modulebytes / sizeof(modulebytes); ++j) {
                    TCHAR buffer[2048] = {}; // バッファサイズは適当
                    if (::GetModuleFileNameEx(process, modules[j], buffer, sizeof(buffer) / sizeof(TCHAR)) == 0) continue;
                    std::basic_string<TCHAR> modulename(buffer);
                    std::basic_string<TCHAR>::size_type pos = modulename.find_last_of(_T('\\'));
                    if (pos != std::basic_string<TCHAR>::npos) modulename = modulename.substr(pos + 1);
                    if (modulename == name) {
                        ::TerminateProcess(process, 0);
                        ++result;
                        break;
                    }
                }
            }
            ::CloseHandle(process);
        }
        
        return result;
    }
}

この関数(を実行するプログラム),32bit 版 Windows では問題なく動作するのですが 64bit 版 Windows ではプロセスを終了させてくれませんでした.何故かなぁと原因を調査していると,「終了させる側のプロセスが 32bit なのに対象プロセスが 64bit」だったからのようです.

Yes, you are correct here. From a 32 bit application it is not possible to enumerate the process on 64 bit Windows. So if you want to run your existing code then you need to compile the code as 64 bit.

Basically the reason why Process Explorer is able to enumerate modules of both 32-bit and 64-bit processes at the same time is, when process explorer launches , it also have a 64 bit version with it .

EnumProcessModules() doesn't work on Windows 2008 Server (64 bit)

Windows Vista 以降だと EnumProcessModulesEx と言う関数が用意されており,この引数に 32bit プロセスを対象とするか 64bit プロセスを対象とするかを指定するフラグがあったので,Vista 以降ならいけるかなぁと期待したのですが 32bit → 64bit の場合は無理でした.

This function is intended primarily for 64-bit applications. If the function is called by a 32-bit application running under WOW64, the dwFilterFlag option is ignored and the function provides the same results as the EnumProcessModules function.

EnumProcessModulesEx function (Windows)

そんな訳で,64bit のプロセスを終了させる方法は,FindWindow() を使ってウィンドウのタイトルからハンドルを取得して終了メッセージを送るか,64bit 版のものを作るしかないようです.