【问题标题】:Get memory address output function获取内存地址输出函数
【发布时间】:2018-11-17 20:34:09
【问题描述】:

我想使用标准 c++ 处理所有 winapi。如何通过地址传递输出?查看o_processName。 GetModuleFileNameExW 函数参数 3 需要 wchar_t 类型。我需要将其转换为 wstring 类型。当我搜索时,可能是将内存地址传递给 GetModuleFileNameExW 而不是类型。

void GetProcessNameById(DWORD i_processId, std::wstring *o_processName)
{
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
    if (hProcess != NULL)
    {
        if (GetModuleFileNameExW(hProcess, NULL, &o_processName, MAX_PATH))
        {
            CloseHandle(hProcess);
        }
    }
}

【问题讨论】:

  • "我想使用标准 c++ 处理所有 winapi" - 这是不可能的。 WinAPI 不是标准C++
  • &o_processName 是一个指向o_processName 的指针,它已经是一个指针,因此将具有std::wstring** 类型。并不是 [GetModuleFileNameExW ](docs.microsoft.com/en-us/windows/desktop/api/psapi/…) 所期望的。永远不要忘记阅读您使用的函数的文档。
  • 即使在此 api 的文档中也明确指出 - 如果您需要 exe 的路径 - 不要使用它。要检索远程进程的主要可执行模块的名称,请使用 GetProcessImageFileName 或 QueryFullProcessImageName 函数。
  • 我检查所有需要输入缓冲区 MAX_PATH 的 windows api。有没有办法在不输入缓冲区的情况下检查进程名称。
  • 所有 windows api 都需要输入缓冲区 MAX_PATH - 当然不是。 有没有办法在不输入缓冲区的情况下检查进程名称 - 你希望 api 自己分配缓冲区并将其返回给你吗?一些 api 这样做,但不是用于查询 exe 名称。在什么问题分配缓冲区?又一次 - GetModuleFileNameExW - 这里有错误的 api

标签: c++ windows visual-studio winapi


【解决方案1】:

您不能将std::wstring(或任何 C++ 容器)直接传递给 Win32 API 函数。 Win32 API 是用 C 接口编写的,因此它对 C++ 类型一无所知。因此,调用 API 时必须使用 C 语义。

在您的示例中,您可以分配一个 C 风格的 WCHAR[] 缓冲区来接收文件名,然后将该缓冲区分配给您的 std::wstring:

void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
    WCHAR szFileName[MAX_PATH];
    DWORD dwLength = 0;
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
    if (hProcess != NULL) {
        dwLength = GetModuleFileNameExW(hProcess, NULL, szFileName, MAX_PATH);
        CloseHandle(hProcess);
    }
    o_processName->assign(szFileName, dwLength);
}

或者,如果您想使用 C++ 容器,您必须预先分配它,然后将其内部数据缓冲区传递给 API:

void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
    std::wstring wFileName;
    wFileName.resize(MAX_PATH);
    DWORD dwLength = 0;
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
    if (hProcess != NULL) {
        dwLength = GetModuleFileNameExW(hProcess, NULL, &wFileName[0], MAX_PATH); // or wFileName.data() in C++17 and later
        CloseHandle(hProcess);
    }
    o_processName->assign(wFileName.c_str(), dwLength);
}

void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
    std::vector<WCHAR> vecFileName(MAX_PATH, 0);
    DWORD dwLength = 0;
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
    if (hProcess != NULL) {
        dwLength = GetModuleFileNameExW(hProcess, NULL, &vecFileName[0], MAX_PATH); // or vecFileName.data() in C++11 and later
        CloseHandle(hProcess);
    }
    o_processName->assign(&vecFileName[0], dwLength); // or vecFileName.data()
}

void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
    std::array<WCHAR, MAX_PATH> arrFileName;
    DWORD dwLength = 0;
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
    if (hProcess != NULL) {
        dwLength = GetModuleFileNameExW(hProcess, NULL, arrFileName.data(), MAX_PATH);
        CloseHandle(hProcess);
    }
    o_processName->assign(arrFileName.data(), dwLength);
}

如果您愿意,可以通过using std::unique_ptr in C++11 and later to ensure the HANDLE is closed automatically when it goes out of scope 更进一步。

最后,您应该使用GetProcessImageFileNameW() 而不是GetModuleFileNameExW():

要检索远程进程的主要可执行模块的名称,请使用 GetProcessImageFileName 或 QueryFullProcessImageName 函数。这比使用 NULL 模块句柄调用 GetModuleFileNameEx 函数更有效、更可靠。

另外,因为GetProcessImageFileName() 只需要PROCESS_QUERY_LIMITED_INFORMATION 访问权限,与PROCESS_QUERY_INFORMATION | PROCESS_VM_READ 权限相比,您更有可能获得该权限,尤其是对于系统/受限进程。

【讨论】:

  • 这修复了原始代码中潜在的句柄泄漏,但引入了新的潜在句柄泄漏。 assign 和 resize 都可以抛出。如果他们这样做了,hProcess 将永远不会被释放。
  • 这段代码没有显示 OP 如何使用带有 win32 API 的标准容器,这是 OP 特别要求的。
  • @joh:代码恰恰证明了这一点。具体来说,你不同意哪一部分?减去异常安全问题,这正是人们将如何做到的。
  • @inspectable 具体如何使用带有 win32 API 的 wstring。
  • @IInspectable 特别是,我引用,“我需要将其转换为 wstring 类型。当我搜索时,可能是将内存地址传递给 GetModuleFileNameExW 而不是类型。”
猜你喜欢
  • 2014-02-18
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多