Under Windows 8 I'm starting an external program but it get stuck as a background process waiting for svchost.exe to return. If I start the same application manually (double click) it starts just fine.
If I run the same code under Windows 7, it works just fine.
I have mainly tried 3 ways of executing the application:
ShellExecute(NULL,L"open","MyApp.exe",NULL,NULL,SW_SHOWNORMAL);
This returns ok but the application freeze waiting for svchost.exe.
Then I tried the Extended version.
SHELLEXECUTEINFO ShExecInfo;
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = Application->MainFormHandle;
ShExecInfo.lpVerb = L"open";
ShExecInfo.lpFile = L"MyApp.exe"
ShExecInfo.lpParameters = NULL;
ShExecInfo.lpDirectory = L"MyWorkDir";
ShExecInfo.nShow = SW_SHOWNORMAL;
ShExecInfo.hInstApp = NULL;
res = ShellExecuteEx(&ShExecInfo);
This also returns ok and I hInstApp is set, but still freeze as before.
Then I tried CreateProcess().
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
res = CreateProcess(L"MyApp.exe",NULL,NULL,NULL,false,0,NULL,L"MyWorkDir",&si,&pi);
This also returns ok and the PROCESS_INFORMATION is filled in correctly, but still it freeze.
RAD Studio shows a debug message when I create the process:
Application "\??\C:\Windows\Program Files (x86)\ ... MyApp.exe" found in cache
Application "\??\C:\Windows\Program Files (x86)\ ... MyApp.exe" cache bypassed reason 0x86
In Windows 8 Task manager I can see that the Process is waiting on svchost.exe to return.
Related
I am trying to launch a new process 'calc.exe' on a new desktop on Windows 10. When I try to switch the desktop the screen becomes black(Looks like its a new desktop with no background). It then switches back to primary desktop as expected and I see the calc.exe launched there. Below is the code snippet. I am using Visual Studio 2015 for development. Why calc.exe does not launch on second desktop?
HDESK originalDesktop;
HDESK secondaryDesktop;
originalDesktop = GetThreadDesktop(GetCurrentThreadId());
LPWSTR secondaryDesktopName = L"Mysecondary";
secondaryDesktop = CreateDesktop(secondaryDesktopName,
nullptr,
nullptr,
DF_ALLOWOTHERACCOUNTHOOK,
DESKTOP_SWITCHDESKTOP |
DESKTOP_READOBJECTS |
DESKTOP_CREATEWINDOW |
DESKTOP_CREATEMENU |
DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALRECORD |
DESKTOP_JOURNALPLAYBACK |
DESKTOP_ENUMERATE |
DESKTOP_WRITEOBJECTS,
nullptr);
//SetThreadDesktop(secondaryDesktop);
SwitchDesktop(secondaryDesktop);
DWORD r = 0;
STARTUPINFO si;
PROCESS_INFORMATION pi;
bool processCreated;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.lpDesktop = secondaryDesktopName;
ZeroMemory(&pi, sizeof(pi));
DWORD dwCreationFlags = CREATE_BREAKAWAY_FROM_JOB; // | CREATE_UNICODE_ENVIRONMENT;
const LPWSTR calculatorExe = L"C:\\Windows\\System32\\calc.exe";
processCreated = CreateProcess(calculatorExe,
nullptr,
nullptr,
nullptr,
TRUE,
0,
//dwCreationFlags,
nullptr,
nullptr,
&si,
&pi);
//Sleep(4000);
if (!processCreated)
{
//logerror
r = GetLastError();
fprintf(stderr, "\n\nError while creating %S process, Code: %d\n\n", calculatorExe, r);
return r;
}
r = WaitForSingleObject(pi.hProcess, INFINITE);
//GetExitCodeProcess(pi.hProcess, &r);
int i=INT_MIN;
while (i < INT_MAX) i++;//Add some delay so that calc.exe //gets launched
//while (i > INT_MIN) i--;
SwitchDesktop(originalDesktop);
///////////////////////
CloseDesktop(secondaryDesktop);
I tried launching notepad.exe and it works. Not sure about calc.exe.
On Windows 10 the Calculator is a Store/UWP app.
calc.exe is a small stub that launches the real Calculator (perhaps using the Application Activation Manager). The real Calculator is launched by a Windows service that knows nothing about your desktop.
That's also the reason your wait is satisfied so fast. calc.exe asks to launch the real Calculator app and exits.
Seemingly simple task: I want to open the standard Windows dialog for picking the application to be used for opening the file, and then wait for this application to finish. The internet tells that ShellExecuteEx is the way to go.
Ok, so here's the code:
SHELLEXECUTEINFO sei;
::ZeroMemory(&sei,sizeof(sei));
sei.cbSize = sizeof(sei);
sei.lpFile = L"path/to/document";
sei.lpVerb = L"openas";
sei.lpParameters = L"";
sei.nShow = SW_SHOW;
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_INVOKEIDLIST ;
BOOL ret = ::ShellExecuteEx(&sei);
DWORD waitResult = ::WaitForSingleObject(sei.hProcess, INFINITE);
But it doesn't work: specifying SEE_MASK_INVOKEIDLIST flag makes hProcess to always be NULL, even if a new process was indeed launched.
How can this be fixed? Thanks in advance!
The shell was never designed to do this and even if it was it would not work 100% of the time because not everything launches a new process (DDE, IShellExecuteHook, IDropTarget, IExecuteCommand etc).
If writing your own dialog is acceptable then you might want to take a look at IEnumAssocHandlers. Raymond Chen recently did a blog post about it.
I'm trying to create a client process in a user session from a service, by using CreateProcessAsUser. But when I debug it with VS 2010, CreateProcessAsUser fails and error code is 0, error message is
cannot create a file when that file already exists
If I distribute it and install with the installer, it seems CreateProcessAsUser occasionally fails with this error. I'm quite curious about what file it is trying to write to.
Personally I don't think it is the client trying to write something. Since CreateProcessAsUser just starts the process and initialize it, then return.
I do use a different way to install the service than the installer does. Would that be the cause?
Here is the code
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\Default";
si.hStdError = m_stdOutWrite;
si.hStdOutput = m_stdOutWrite;
si.dwFlags |= STARTF_USESTDHANDLES;
LPVOID environment;
BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE);
if (!blockRet) {
throw XArch(new XArchEvalWindows);
}
DWORD creationFlags =
NORMAL_PRIORITY_CLASS |
CREATE_NO_WINDOW |
CREATE_UNICODE_ENVIRONMENT;
BOOL createRet = CreateProcessAsUser(
userToken, NULL, LPSTR(command.c_str()),
sa, NULL, TRUE, creationFlags,
environment, NULL, &si, &m_processInfo);
DestroyEnvironmentBlock(environment);
CloseHandle(userToken);
I use the following STARTUPINFO structure in my call to CreateProcess. Do I need to call CloseHandle on hStdError and hStdInput after the process ends?
startupInfo.cb = sizeof(startupInfo);
startupInfo.cb = sizeof(si);
startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startupInfo.hStdOutput = NULL;
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startupInfo.wShowWindow = SW_HIDE;
Since you didn't open those handles (that's not what GetStdHandle
does), you don't need to close them (maybe you want to close them
for some other reason, but it's unlikely). (Note: even if you did
open the handles, you don't have to wait for the process to exit
before you close them: once they are inherited, closing them in parent
process has no effect on the child).
Note that hStdOutput should be INVALID_HANDLE_VALUE instead of
NULL: that's the convention for passing the absence of a handle in STARTUPINFO.
To the question "do you need to?" - the simple answer is "no".
When a process ends all handles connected to it are destroyed in Windows OSs.. if you are creating a process within a process (I don't even want to try that in C, but it's quite simple in C#) then it would be safer to make sure the child process cleans up after itself before (or on-) termination.
A way to test this would be to try and access your handle after you've terminated your child process in your parent process.
I have an application that aids people with disabilities. In order to work, it tracks the what window is currently in the foreground. Normally, I use this function to get process executable.
bool GetWindowProcessExe2(HWND hwnd, wxString& process_exe)
//LPTSTR buf, DWORD size)
{
DWORD result = 0;
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
if (HANDLE process =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid))
{
char buff[512];
LPTSTR pbuff = buff;
result = GetModuleFileNameEx(process, 0, pbuff, 512);
if(result == 0)
{
//failed.
wxLogError("GetModuleFileNameEx failed with error code %d", GetLastError());
}
CloseHandle(process);
process_exe = fromCString(pbuff);
}
return result > 0 ? true : false;
}
Unfortunately, if the foreground window is the Vista file manager window (the window that opens when you click Start->Computer), GetModuleFileNameEx() fails with error code 299 which says I don't have privileges for this action. My code works for any regular application but not for the windows built in window (the file explorer). I need to know when this window is forefront. Is there another way to do it? I tried reading the window title but that just returns the current directory being shown. Any ideas?
I'm not sure why this isn't working for explorer, but error 299 is ERROR_PARTIAL_COPY, meaning that attempting to read the module name out of explorer is failing.
On Vista, prefer QueryProcessImageFileName and only open the process with PROCESS_QUERY_LIMITED_INFORMATION - your code will work in more cases.
WCHAR exeName[512];
DWORD cchExeName = 512;
HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
QueryFullProcessImageName(process, 0, exeName, &cchExeName);
EDIT: I also got ERROR_PARTIAL_COPY with your code running on 64-bit, but only when the querying process was 32-bit. 64-bit/64-bit worked fine.
Looks like a 32 bit process can call GetModuleFileNameEx only on othere 32 bit processes. If you try to call it on 64 bit processes it fails with ERROR_PARTIAL_COPY.On a 64 bit platform make the calling process 64 bit and you should be able to call GetModuleFileNameEx on both 64 and 32 bit processes.