I want to use the Windows API to launch other programs (.exe
, .url
, .lnk
) on my computer, so I use the following to do so:
int main() {
//const std::wstring& programPath = L"C:\\Users\\ghost\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Steam\\Steam.lnk";
const std::wstring& programPath = L"C:\\Program Files\\Everything\\Everything.exe";
// Prepare the command line to run the program using cmd.exe
std::wstring commandLine = L"cmd.exe /c start \"\" \"" + programPath + L"\"";
// Log the command line to ensure it is correct
qDebug() << "Attempting to run command: " << commandLine;
// Prepare the STARTUPINFO structure
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Create a writable copy of the command line
std::vector<wchar_t> commandLineBuffer(commandLine.begin(), commandLine.end());
commandLineBuffer.push_back(0);
// Create the process
if (!CreateProcess(
NULL, // Module name (use command line directly)
commandLineBuffer.data(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW | DETACHED_PROCESS, // No console window, detached process
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
) {
qDebug() << "Failed to create process. Error: " << GetLastError();
} else {
// Close process and thread handles to ensure they are completely detached
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
qDebug() << "Process created successfully: " << commandLine;
}
int t;
std::cin >> t;
return 0;
}
Launching .url
and .lnk
files with this code works fine.
But, when I want to use this code to launch an .exe
file, I found that the folder where the application is located still prompts "This folder is in use" when the application finishes running. So I used the Resource Monitor to find out that the handle of the application that was launched with this code still pointed to this folder, which made it impossible to rename the folder.
I started the everything.exe
program using the above code, and I can see that the handle to everything.exe
still points to this folder, so when I finish running this program, I still can't delete and rename this folder. As you can see from the picture below:
I've also tried separating using ShellExecute
, and separating using ShellExecuteEx
, neither of which work.
Now I want the handle to everything.exe
to no longer point to this folder to make sure I can delete or rename this folder. What should I do?
The issue is that you passed NULL
as working directory, so the working directory will be inherited from your launcher program. If you start your launcher from the directory it's in (for example by double-clicking the file in Explorer), this then means that the process you start from it will also have this directory as working directory so not only will there be a handle to it but also relative paths will get resolved with that directory as base (which may be unexpected in some cases).
The solution is to extract the directory part of the path of the program you are launching and passing this as working directory. So if you are launching, say, C:\Windows\System32\notepad.exe
, you'd need to set its working directory to C:\Windows\System32
. (This is what would also happen if you'd launch the program from Explorer.)
std::filesystem::path::parent_path
will help you with this task.