-2

I want to work all winapi with standart c++. how to pass output with address? look o_processName. GetModuleFileNameExW function paremeter 3 need wchar_t type. i need to convert it to wstring type. as i search the possible is to pass memory address to GetModuleFileNameExW not the type.

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);
        }
    }
}
  • "*I want to work all winapi with standart c++*" - that's not possible. WinAPI is **not** standard `C++` – Fureeish Nov 17 '18 at 20:37
  • 1
    `&o_processName` is a pointer to `o_processName`, which already is a pointer and will therefore have the type `std::wstring**`. Not really what [`GetModuleFileNameExW` ](https://learn.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getmodulefilenameexa) expect. Never forget to read the documentation of the functions you use. – Some programmer dude Nov 17 '18 at 20:39
  • even in documentation of this api clear stated - if you need path of exe - not use it. To retrieve the name of the main executable module for a remote process, use the `GetProcessImageFileName` or `QueryFullProcessImageName` function. – RbMm Nov 17 '18 at 20:47
  • i check all windows api need to input buffer MAX_PATH. is there ways to check process name without input the buffer. – stephen ju Nov 17 '18 at 20:52
  • *all windows api need to input buffer MAX_PATH* - of course no. *is there ways to check process name without input the buffer* - you want that api allocate buffer yourself and return it to you ? some api do this, but not for query exe name. in what problem allocate buffer ? and again - `GetModuleFileNameExW` - wrong api here – RbMm Nov 17 '18 at 20:56
  • and `CloseHandle(hProcess);` need call if `hProcess != NULL` - even if `GetModuleFileNameExW` or any another code inside fail – RbMm Nov 17 '18 at 21:01
  • by the way, u knows api to get process name by pid? like **notepad.exe**. – stephen ju Nov 17 '18 at 21:03
  • GetProcessImageFileName return device path process. and queryfullprocess return path too. i just need the name process. – stephen ju Nov 17 '18 at 21:06
  • if you want name without path - simply search for last \ - nothing can be more simply. – RbMm Nov 17 '18 at 21:07
  • and from where you get pid (i_processId) ? – RbMm Nov 17 '18 at 21:08
  • there's function that i create. i need this function to work. is there condition i need t his function. – stephen ju Nov 17 '18 at 21:10
  • @RbMn in no way do I disagree with the information you have stated, but I would like to add everyone starts somewhere and we all took baby steps to get where we are with our own win32 API knowledge. I find, quite often, that telling someone that they are doing things incorrectly without providing them a clear solution simply is counter productive to the ethos of SO. – johnathan Nov 18 '18 at 00:11

1 Answers1

2

You cannot pass a std::wstring (or any C++ container) directly to a Win32 API function. The Win32 API is written with a C interface, and so it knows nothing about C++ types. As such, you must use C semantics when calling the API.

In your example, you can allocate a C style WCHAR[] buffer to receive the filename, and then assign that buffer to your 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);
}

Alternatively, if you want to use a C++ container, you have to preallocate it and then pass its internal data buffer to the 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);
}

If you want, you can take this a step further by using std::unique_ptr in C++11 and later to ensure the HANDLE is closed automatically when it goes out of scope.

And lastly, you should be using GetProcessImageFileNameW() instead of GetModuleFileNameExW():

To retrieve the name of the main executable module for a remote process, use the GetProcessImageFileName or QueryFullProcessImageName function. This is more efficient and more reliable than calling the GetModuleFileNameEx function with a NULL module handle.

Also, because GetProcessImageFileName() requires only PROCESS_QUERY_LIMITED_INFORMATION access rights, which you are more likely to be able to obtain than PROCESS_QUERY_INFORMATION | PROCESS_VM_READ rights, especially for system/restricted processes.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • This fixes the potential handle leak in the original code, but introduces new potential handle leaks. Both [assign](https://en.cppreference.com/w/cpp/string/basic_string/assign) and [resize](https://en.cppreference.com/w/cpp/string/basic_string/resize) can throw. If they do, `hProcess` is never released. – IInspectable Nov 18 '18 at 03:45
  • this code does not show thw OP how to use a standard container with win32 API, which is what the OP specifically asked for. – johnathan Nov 18 '18 at 14:02
  • 1
    @joh: The code demonstrates precisely that. Specifically, which part do you disagree with? Minus the exception safety issue, this is precisely, how one would do it. – IInspectable Nov 18 '18 at 14:40
  • @inspectable specifically how to use a wstring with win32 API. – johnathan Nov 18 '18 at 14:47
  • @IInspectable specifically , and i quote, " i need to convert it to wstring type. as i search the possible is to pass memory address to GetModuleFileNameExW not the type." – johnathan Nov 18 '18 at 14:48
  • @joh: You lost me. The code demonstrates precisely, how to interface with C code, using standard C++ containers. Again, *specifically*, where do you feel the code provided in this answer is wrong/inaccurate/doesn't address the question/something else? – IInspectable Nov 18 '18 at 14:52
  • @IInspectable https://stackoverflow.com/questions/53361844/openprocess-the-handle-is-invalid-closehandle-not-work. possible duplicate? – johnathan Nov 18 '18 at 14:59
  • I fixed the handle leak on throw, and added more examples of using various C++ containers to get the filename – Remy Lebeau Nov 18 '18 at 19:30