I have two application. I will just call them A and B. I have access to the code of application A.
I want to launch the applicaiton B and open a file in that application from A. I am using
CreateProcess method to acheive it. But the application B is not getting opened completely.
I am not sure whether there are any common dlls or other dependencies between these two applications.
The code that I use to open the applicaiton B form A is:
std::wstring appBPath(L"C:\\B.exe");
std::wstring filePath(L"C:\\file.pdf");
std::wstring cmdLineCommand = L"\"" + appBPath+ L"\" \"" + filePath + L"\"";
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInfo;
// set the size of the structures
SecureZeroMemory( &startupInfo, sizeof(startupInfo) );
startupInfo.cb = sizeof(startupInfo);
SecureZeroMemory( &processInfo, sizeof(processInfo) );
CreateProcess( NULL, // No module name (use command line)
&cmdLineCommand[0], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // New process has a new console
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&processInfo ); // Pointer to PROCESS_INFORMATION structure
The exe file starts to load but it gets stuck during the initialisation. But, the application B doesn't terminate.
It goes to some inconsistent state. This issue is happens only only for application A that's installed from it's installer.
It doesn't occur when I run the release or debug build. For the release and debug build we are using VC10. But for installer
build we use VC12. I am not sure on the compiler optimization that are there in place for the installer build.
The CreateProcess function returns success.
Thread state of the application B from process explorer:
Related
I have a third party console application in term as "reg.exe". When I run it, it shows me a text message. I want to use this string in my application.
How do I get this string?
I want to use CreatProcess to execute "reg.exe",
CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
Then use
WaitForSingleObject( pi.hProcess, INFINITE );
to wait it to be finished.
I am trying to redirect the stdout of a child process in Windows. Both are console programs. I don't have the source code of the child process, so I can't force it to flush the buffer. As discussed here and here, for the implementation of printf and similar, the C runtime buffers everything except consoles and printers. So the solution is apparently to create a console screen buffer using, appropriately enough, CreateConsoleScreenBuffer. I'm using the approach from codeproject.
PROCESS_INFORMATION pi;
HANDLE hConsole;
const COORD origin = { 0, 0 };
// Default security descriptor. Set inheritable.
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; // So the child can use it
// Create and initialize screen buffer
hConsole = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, // Desired access
FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode to child processes
&sa, // SECURITY_ATTRIBUTES
CONSOLE_TEXTMODE_BUFFER, // Must be this.
NULL // Reserved. Must be NULL
);
DWORD dwDummy;
FillConsoleOutputCharacter(hConsole, '\0', MAXLONG, origin, &dwDummy)
Now I direct the child's stdout to the console and start the process
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES; // first one prevents cursor from showing loading.
si.hStdOutput = hConsole;
//...
// Get the command line and environmental block
//...
if (! CreateProcess(
NULL, // module name.
(char*)command_line.c_str(), // command line
NULL, // process SECURITY_ATTRIBUTES
NULL, // thread SECURITY_ATTRIBUTES
TRUE, // inherit handles
NULL, // creation flags
enviros, // environmentBlock (enviros=NULL for testing)
cDir, // working directory
&si, // STARTUP_INFO object
&pi // PROCESSINFO
) ){
auto test = GetLastError();
CloseHandle(hConsole);
return false;
}
CloseHandle(pi.hThread);
Then, in a loop, I can use ReadConsoleOutputCharacter to grab output, as shown at the codeproject link. It looks like
//... some initialization
GetConsoleScreenBufferInfo(hConsole, &csbi);
DWORD count = (csbi.dwCursorPosition.Y - lastpos.Y)*lineWidth + csbi.dwCursorPosition.X - lastpos.X;
LPTSTR buffer = (LPTSTR)LocalAlloc(0, count * sizeof(TCHAR));
ReadConsoleOutputCharacter(hConsole, buffer, count, lastpos, &count);
DWORD dwDummy;
FillConsoleOutputCharacter(hConsole, '\0', count, lastpos, &dwDummy);
//... Now move the cursor and grab the data from `buffer`
On Windows 7/8.1 this works fine for all programs. On Windows 10, some programs seem to be bypassing the supplied handles and printing directly to the parent console, preventing me from grabbing the output as I need.
I do have an additional clue. If I force the process to create a new console window, i.e.
CreateProcess(NULL, (char*)command_line.c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, enviros, cDir, &si, &pi)
but still redirect the handles in the STARTUPINFO object, the new console will display a single line that says The system cannot write to the specified device, which just happens to be the exact wording of Windows error code ERROR_WRITE_FAULT = 29 in the MSDN docs. This happens only for those programs which aren't working as expected. Other programs, the new console is blank and they still function as expected.
My first thought is a permissions problem, but I have wide open permissions on the directories of the relevant executables.
Things I've tried
A different computer with Windows 10
Different versions of MS Visual C++ runtime
Setting the working directory explicitly in CreateProcess
Adding a super-permissive DACL to a SECURITY_ATTRIBUTES object passed to CreateProcess
Adding a super-permissive DACL to a SECURITY_ATTRIBUTES object passed to CreateConsoleScreenBuffer
Moving everything to a newly created directory under my Windows user directory
Running as administrator
Deeper
Thank you #PaulSanders for your suggestion.
To aid with anyone who might want to assist, I've made available a modified version of the RTConsole code from the codeproject page. It should compile in Visual Studio with just a retarget, I think. Around line 135, I've prepended a little string to the front of the output which takes the expected path. I've provided a pre-compiled version in there for convenience, as well.
One example of software that doesn't work is EWBF miner. For a quick test using the code I provided above, you could run
RTConsole2.exe "path\to\ewbf.exe" --help
You'll see that the prepended flag is not present in the output.
On the other hand, with ccminer, you'll get the expected behavior when running
RTConsole2.exe "path\to\ccminer.exe" --help
The new console implementation in Windows 10 has a bug in which high-level WriteConsole and WriteFile to a non-active screen buffer instead always writes to the active screen buffer. Low-level WriteConsoleOutput[Character] works correctly. Using the legacy console also works. You can enable the legacy console in the properties dialog.
Note that a process cannot use an inherited handle for a screen buffer in the parent's console if it allocates a new console due to the CREATE_NEW_CONSOLE flag. Trying to write to the screen-buffer file will fail because it's not bound to the caller's attached console (i.e. instance of conhost.exe).
Console files that are bound include "CON", "CONIN$", "CONOUT$", and a new screen buffer from CreateConsoleScreenBuffer. There are also unbound input and output console files, which are set as the standard handles when allocating a new console (e.g. via AllocConsole()). These handles access the input buffer and active screen buffer of any attached console [*]. Note that a process can have handles for console files that are bound to multiple consoles and can switch between consoles using AttachConsole.
Note also that some programs open "CONOUT$" instead of writing to the StandardOutput and StandardError handles, especially if they require a console instead of whatever the standard handles might be (e.g. a pipe or disk file). In this case it is not enough to set hStdOutput in STARTUPINFO. You have to temporarily make the new screen buffer active via SetConsoleActiveScreenBuffer. This does not affect the caller's standard handles. It sets the active screen buffer in the attached console, which is what "CONOUT$" opens. The previous screen buffer can be restored after the child process exits, or after you know the child has already opened and written to the new screen buffer.
[*] In Windows 8+, these console files are implemented by the condrv.sys device driver and opened on "\Device\ConDrv". They are respectively named "Console", "CurrentIn", "CurrentOut", "ScreenBuffer", "Input", and "Output". The filename for the console connection itself is "Connect". Internally the latter is opened as the process ConsoleHandle, which is used implicitly by the console API in some cases (e.g. GetConsoleWindow, GetConsoleCP, and GetConsoleTitle).
I am trying to use the CreateProcess() function in order to launch an .exe application that is in a folder in my root directory (the directory where my VS solution is). Seems simple right? It probably is but I can't for the life of me notice what I have done wrong. Every time I try to launch the .exe I get the error message "CreateProcess failed code 2" which means that the .exe file I am trying to launch cant be found.
My code:
void HavNetProfiler::LaunchClumsy()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess((LPCTSTR)"Clumsy\\clumsy.exe", // No module name (use command line)
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Am I using this function wrong? Have I misunderstood how it works or have I simply missed some minor detail? I am calling the function LaunchClumsy() in a file that is placed in a different folder (that folder exists in the root folder just like the "Clumsy" folder though). Would that make a difference?
Thanks!
There are 2 immediate bugs in the code:
The LPCTSTR cast is wrong. If your code does not compile without that cast, you have passed an argument with the wrong character encoding. Change it to L"Clumsy\\clumsy.exe" to explicitly pass a wide-character string.
Using a relative path is very likely to fail. The system searches starting from the current working directory. That is a process-wide property, that can be altered by any thread, at any time. Use an absolute path instead.
I have two separate executable files, A.exe & B.dontrun, where A.exe launches B.dontrun after doing some initialization. The two processes then communicate to each other and A.exe exits after B.dontrun exits. This all behaves fine using CreateProcess and passing the executable name as the first argument when B.dontrun is named B.exe but if B.dontrun is named anything else (B.ex_ or B.bin) CreateProcess doesn't return an error, but the process isn't launched either.
I'd like B.dontrun to be named something that doesn't encourage people to run it directly, when they look in the directory they see A.exe and B.dontrun and there isn't confusion of which executable that they should be running.
At least up till and including Windows XP, the [cmd.exe] command interpreter recognizes a PE executable as such regardless of the filename extension, and runs it.
Which is one reason why it's not a good idea to start a text document with the letters "MZ"... ;-)
And which means that it’s not a good idea to try to prevent execution via filename mangling.
Instead, make the other process a DLL, and launch it via rundll32.
Cheers & hth.,
You need to specify the exe name in the cmd line argument rather than in the application name.
This works:
STARTUPINFO info;
ZeroMemory(&info, sizeof(info)); info.cb = sizeof(info);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
TCHAR sz[1000]; // Note: lpCommandLine must be writable
lstrcpy(sz, L"c:\\users\\serge\\desktop\\notepad.dontrun");
CreateProcess(NULL, sz, NULL, NULL, FALSE, 0, NULL, NULL, &info, &pi);
printf("Error = %u\n", GetLastError());
This indeed gives a File not found error (2):
STARTUPINFO info;
ZeroMemory(&info, sizeof(info)); info.cb = sizeof(info);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
CreateProcess(L"c:\\users\\serge\\desktop\\notepad.dontrun",
NULL, NULL, NULL, FALSE, 0, NULL, NULL, &info, &pi);
printf("Error = %u\n", GetLastError());
Note: Tested on Win7 x64
You should create the file as hidden.
CreateFile has an attribute you can use
FILE_ATTRIBUTE_HIDDEN 2 (0x2) The file is hidden. Do not include it in an ordinary directory listing.
Documentation here: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
I am trying to create a program that calls another process using CreateProcess. After some problems, I change my program to just open a known program:
if( !CreateProcess( (LPWSTR)"C:\\Program Files\\Opera\\Opera.exe", // No module name (use command line)
NULL, ,
// Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
I found this example in msdn, but every time I run my program, windows (Vista) shows a error msg: The program stop running...
Does anybody know what is the problem?
Regards,
Leandro Lima
This line is wrong:
(LPWSTR)"C:\\Program Files\\Opera\\Opera.exe"
LPWSTR is a typedef for wchar_t*. So you're casting a plain string (array of chars, which will decay to a const char*) to a wchar_t*. The end result is likely not even null-terminated!
Either use CreateProcessA and drop the cast, or use a wide string:
L"C:\\Program Files\\Opera\\Opera.exe",