C++ Retrieve Content From a Remote Console Application - c++

Introduction:
I'm an administrator currently working on the dedicated servers of the game "Sniper Elite V2". SEV2's dedicated servers are running under windows in a console application. We are able to run this application under Linux too, with wineHQ. Everything is good, excepted that the console is launched in a new window, so no way to have the console inputs/outputs (link: http://img802.imageshack.us/img802/650/sev22.png). Moreover, we can read (with an HEX editor) that "This program cannot be run in DOS mode". My objective is to bring back DOS compatibility.
My idea is to create another console application written in C++ (with CodeBlocks).
This "Hook" should retrieve the content (text) of the dedicated server "window" and will display it, with the possibility of course to input commands to the dedicated server console. Like that, we will be able to work with inputs/outputs both on Windows and Linux.
I took the time to draw a little schema : http://img195.imageshack.us/img195/3017/29585679.png
My question is: How to do this ? Which functions should I use ?
At this point, I'm stuck. I've tried the following approaches :
FUNC "AttachConsole" has failed.
The following pseudo-code has failed too:
mainWindow = FindWindow( TEXT("ConsoleWindowClass"), NULL) );
console = FindWindowEx( mainWindow, NULL, TEXT("ConsoleWindowClass"), NULL );
SendMessage(
console,
WM_GETTEXT,
sizeof(buffer) / sizeof(TCHAR),
(LPARAM)buffer);
I'm using a tool called "WinSpy++" to help me, but the tool is not able itself to retrieve/input data to the Sniper Elite V2 Dedicated Server.
Any ideas/examples/reflections is welcome :-)

"This program cannot be run in DOS mode"
You make a mistake. Don't mix terms "DOS mode" and "Console". Windows console is NOT a DOS mode. Console is native terminal, where you can run any windows application 32/64 bit, written for console subsystem. "DOS mode" is pre Windows operating system, e.g. DOS, TR-DOS, FreeDOS and so on.
As for question, one console app can not work with two consoles simultaneously.
Upd
Seems that server was builded for GUI subsystem and creates console with AllocConsole.
Run server with 'CreateProcess'
Wait a little while new console wIndow appears.
Call 'FreeConsole' and 'AttachConsole(ServerPID)'
Old
So, if you want to read console_1 from process belonging to console_2, you must
start third process, for example with DETACHED_PROCESS
call FreeConsole (required) and AttachConsole(RootPidFromConsole_1)
communicate between third process and console_2's process (pipes, shared memory, ...)
this works in windows.

Related

Createprocess() for a GUI application that also writes to console

I am coding on a native app that uses CreateProcess to launch a GUI based WPF application. In the lpCommandLine parameter, I am also including the command line info along with the application name. Incidently the WPF application to launch also adds a newline to console window whenever any command line parameters are sent to it. Due to this, CreateProcess() is relaunching the application every time I close it. Any help how to solve this issue?
I also searched several links like the one below but nothing really helps to solve my issue.
Can one executable be both a console and GUI application?`

Using the console in a GUI app in windows, only if its run from a console

My application is a GUI app that has helpful (though optional) information through the terminal (via cout).
In Windows I either have a console appear (by compiling as a console app, or allocating it dynamically) or I don't.
My intention is to make use of the console IF it is being run from the console, but ignore the console completely if it was not. (Essentially what happens in Linux and OS X).
I do not wish to redirect to a file (and in the case of using cin, this is not a viable solution anyway).
Is there a way to attach a GUI app in Windows to the console it is run from, if and only if it is run from a console?
and in the case of using cin, this is not a viable solution anyway
This is the killer detail in your question. It is simple on paper, just first call AttachConsole(ATTACH_PARENT_PROCESS) to try to attach to an existing console. That will fail when your program got started from a GUI program like Explorer or a desktop shortcut. So if it returns FALSE then call AllocConsole() to create your own console.
Using cin is a problem however. The command processor pays attention to your EXE and checks if it is console mode app or a GUI app. It will detect a GUI app in your case and then doesn't wait for the process to complete. It displays the prompt again and waits for input. You will then also wait for input but you'll lose, the command processor got there first. Your output is also intermingled with the command prompt, the easy problem to solve.
There's a simple workaround for that, your user should start your program with start /wait yourapp to tell the command processor to wait for the process to complete. Problem is: nobody ever uses that. And the user will not realize what happens when they type input, intending it to go into your program but it is actually interpreted by the command processor. Producing a mystifying error message or formatting the hard drive.
Only two good ways to solve this unsolvable problem. Either build your program as a console mode app and call FreeConsole() when you find out you want to display a GUI. Or always call AllocConsole(). These are not great alternatives. The first approach is the one used by the Java JVM on Windows. One of the oldest bugs filed against the JVM and driving Java programmers completely batty from the flashing console window.
The third alternative is the only decent one, and the one you don't want, create another EXE that will always use the console. Like Java does, javaw.exe vs java.exe.
A trick is possible, you can rename that file from "yourapp2.exe" to "yourapp.com". It will be picked first when the user types "yourapp" at the command line prompt, a desktop shortcut can still point to "yourapp.exe". Visual Studio uses this trick, devenv.com vs devenv.exe.
You can check CONSOLE_SCREEN_BUFFER_INFO (via GetConsoleScreenBufferInfo) on startup to determine if you've been run from within an existing console. If the buffer's position is 0,0, you were run from outside of the console. For details, see this Microsoft Knowledgebase Article which describes the process.
In order for this to work, you need to compile your application as a console application (using /SUBSYSTEM:CONSOLE), and then detach yourself from the console if the application started a new console (buffer at 0,0). This will cause the program to properly "attach" to the calling console when launched from a command line.
As others have pointed out you have to create a console app and a window app. So, you'd end up with console.exe and app.exe. To make it less obvious at the command-line, you can take advantage of the PATHEXT trick like devenv does. cmd.exe treats a file as a command if its extension is in the PATHEXT environment variable. COM is there by default so you could rename console.exe as app.com, allowing the command app to start the console app attached to the current console.
Note: Of course, a console app can show a GUI if desired.
The difference in the build between app.com and app.exe depends on your build system but it could just be the one attribute that sets the output type. With msbuild (for .vcxproj files), it's just a matter of another build configuration.
you can create an application in console that get a line using argc and prints it;
////
int main(int argc, char *argv[])
{
//here print argv....using cout or printf
}
save the file as console.exe in the folder of your app.
now in your app if you want to see any line in console you can call the command
system("console.exe this is the line i want to print and see in console");

Embed command line inside window?

Is it possible to embed system command line right inside your application window?
I want to be able to have the command line take some space on the bottom of my C++ application, and my application to take the above space. Ideally it should work on Mac, Linux and Windows, but for starters Windows is the primary goal as I am developing on it.
Speaking for Windows, the Windows console window is "special" in that it gets special treatment, different than any other window on the system. You will not succeed in manipulating it for your own use. For a good example, try using Spy++ on a console window.
Note that the window created with AllocConsole is not a command-line interpreter, it's just a console window.
You should implement your own console window, and as far as interpreting the commands I can think of a few options to explore depending on what you expect, behavior-wise and complexity-wise:
Delegate commands to a hidden cmd.exe
Interpret commands yourself
There are probably open-source solutions for command line interpreting.
In Windows, you can do that using some WinAPI functions like ShellExecute and CreateProcess (there are a few others that I don't remember). You get the command string from your GUI, pass it to one of these WinAPI functions, then send the output back to your GUI.
You want to do this on multiple platforms, so I would suggest making a generic module (class or namespace of functions, whatever fits you best) that allows using the OS terminal agnostic of the actual underling OS. Then. when you want to port your app to another OS, you just change the implementation of this module.
Note: Boost has (had?) a library under development that made running shell commands easier, Boost.Process. But it's currently on version 0.4 and hasn't been updated since October 4, 2010 (even though its status is still "on going").

The problem of attachconsole

I need to make a windows GUI application can run in console, so I attach the console to the process when the application is invoked with a command line. However, after the application exit, the console prompt with the path doesn't show unless the ENTER key is pressed. Is there any way that the prompt with the path can directly show up without pressing the enter key? Thanks.
Short answer: This is not possible.
Long answer: Well, it is sort of possible if you are willing to relax your requirements a little bit. You basically have three options:
What you have done already. You can attach GUI application to a console but cmd.exe will not wait for your application to exit.
Create a GUI application and open console in the GUI application. The console will only last as long as you application.
Or you can restructure your application/source a bit and provide two executables, GUI one that starts GUI directly, another that is console executable.
In C#, I use SendKeys.SendWait("{ENTER}"); to do that. I think in C++, the keybd_event function does something similar.
Like Autodesk Maya with MayaBatch, you can build a small console application which basically run your GUI application with CreateProcess and wait with WaitForSingleObject.
You will have to use this "batch" version of your application in the console.

How to know if the windowstation attached is interactive?

I am writing a program that can be loaded by another service (under our control), or by the logged-on user. The program needs to know if the window station is interactive in order to display dialogs. I know GetProcessWindowStation function, but this one returns a handle. Is there a way to find out?
The interactive window station is always winsta0. So you need to get the window station name to determine it. Here is some pseudo code:
wchar_t buffer[256] = {0};
DWORD length = 0;
GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, buffer, 256, &length);
if (!lstrcmp(buffer, "winsta0")) {
// Interactive!
}
From http://msdn.microsoft.com/en-us/library/ms687096(VS.85).aspx:
The interactive window station, Winsta0, is the only window station that can display a user interface or receive user input
I suggest having the service pass command line parameters that let the program know it was launched by the service and not a user.
Please note that this only works on Windows XP (and then only sometimes) - on Windows Vista and beyond, services run in a separate session from interactive users, so you'll never be able to attach to the console on those OSs.
In addition on Windows XP, your application won't work if there are multiple users on the machine (Fast User Switching) because only the first user is logged onto session 0 (where services run).
You'd be far better off splitting your service into two pieces - the service which does the work and a small piece of code which runs as a task (using the Win32 task scheduler APIs) that runs the UI.