I have a client server application. Using the CreateProcess()
function, a new process is created on the server, which is actually like a remote console. The client sends a command, it is executed in the server console and returns the result back to the server. To communicate with the console, I use WriteFile()
and ReadFile()
. This part works great.
But I also need to be able to run FarManager in the server console and manage it.
I am able to run FarManager on the server using an environment variable, or by directly specifying it when creating a process. But after running the program, I can't issue any commands (for example, pressing the down arrow). It looks like the current implementation of pipes is not suitable for this task.
Can anyone suggest what might be useful for this?
CreateProcess function:
I am not attaching all the related structures, because the problem does not seem to be in the process itself
TCHAR szCmdline[] = TEXT("C:\\Windows\\System32\\cmd.exe");
TCHAR prog[] = TEXT("D:\\Program Files\\Far Manager x86\\Far.exe");
// Create the child process.
bSuccess = CreateProcess(
prog, // far
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NEW_CONSOLE, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&si, // STARTUPINFO pointer
&pi); // receives PROCESS_INFORMATION
WriteToPipe function:
bool WriteToPipe(char* com)
{
OVERLAPPED osWrite = { 0 };
DWORD dwWritten;
DWORD dwRes;
BOOL fRes;
// Create this write operation's OVERLAPPED structure's hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL) {
// error creating overlapped event handle
throw std::exception("Error creating overlapped event");
}
// Issue write.
if (!WriteFile(console_stdIn_wr, com, strlen(com), &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
std::cout << " WriteFile failed, but isn't delayed" << std::endl;
fRes = FALSE;
}
else {
// Write is pending.
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch (dwRes)
{
// OVERLAPPED structure's event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(console_stdIn_wr, &osWrite, &dwWritten, FALSE))
fRes = FALSE;
else
// Write operation completed successfully.
fRes = TRUE;
break;
default:
// An error has occurred in WaitForSingleObject.
// This usually indicates a problem with the
// OVERLAPPED structure's event handle.
fRes = FALSE;
break;
}
}
}
else {
// WriteFile completed immediately.
fRes = TRUE;
}
CloseHandle(osWrite.hEvent);
return fRes;
}
I don't understand how I can issue commands to the open FarManager? Which function is worth looking at, and is the current implementation of pipes suitable for this?
I am attaching my solution based on the advice of @YurkoFlisk. Maybe it can be useful for someone
//Execute command in FarManager
//nVirtKey - code of virtual key to run in far
void RunFar(int nVirtKey){
std::cout << "Key code "<< nVirtKey << std::endl;
//Create structure with buttons and their state
INPUT inputs[2] = {};
ZeroMemory(inputs, sizeof(inputs));
//Set key, that must be "pressed"
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = nVirtKey;
//Set state of key
inputs[1].type = INPUT_KEYBOARD;
inputs[1].ki.wVk = nVirtKey;
inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
//Set position of window with FarManger to the foreground (by the handle of window)
SetForegroundWindow(hwnd);
//Send key structure to window
UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
}