GetModuleFileNameEx uses ReadProcessMemory in order to obtain the desired information.
Use the following code to obtain a process handle with all the access rights needed -
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
In my opinion, a better alternative is to use QueryFullProcessImageName since it requires a process handle that only needs the PROCESS_QUERY_LIMITED_INFORMATION right.
Additionally, you should read nf-processthreadsapi-getexitcodeprocess
It says, "Important The GetExitCodeProcess function returns a valid error code defined by the application only after the thread terminates. Therefore, an application should not use STILL_ACTIVE (259) as an error code. If a thread returns STILL_ACTIVE (259) as an error code, applications that test for this value could interpret it to mean that the thread is still running and continue to test for the completion of the thread after the thread has terminated, which could put the application into an infinite loop."
The posted code makes exactly this mistake by obtaining the exit code of an active process and passing it to TerminateProcess.
And it is possible for TerminateProcess to return before the target process has been terminated. To ensure that the target process has actually terminated you should call WaitForSingleObject with the process handle. When that function returns WAIT_OBJECT_0 the results of calling GetExitCodeThread will reflect the exit code of the terminated process.