Hey,
This issue was addressed before but not in this angle. I'm trying to control a Python application with C#. The application runs an unknown time and I need to hold the main C# application form until It "knows" when the Python application is done processing.
I should mark that the Python Application has its own GUI which i'm trying to keep.
So far, I've used:
ProcessStartInfo processStart= new System.Diagnostics.ProcessStartInfo(#app);
processStart.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
processStart.UseShellExecute = false;
processStart.RedirectStandardOutput = true;
processStart.CreateNoWindow = true;
Process myProcess = Process.Start(processStart);
Then I send a couple of "SendKey" methods including some TAB and ENTER.
Furthermore, as you can probably infer from the code I'm trying to make the entire Python process hidden – I did succeed in open\close the Python application but didn't succeed in controlling it at all. Any suggestions?
Redirect stdin and the push characters in that way (rather than sendkeys)?
Have you looked into IronPython - it allows you to execute python code from within you .NET application natively.
SendKeys can only send keystrokes to the active application. Since you are forcing it to start without creating a window it can't receive the SendKeys.Send() messages. It sounds like what you really want is to use the functionality of the python code without presenting any UI from that application to your users.
You could approach this in one of 2 ways:
My first reccommendation is that you write a simple python script that imports the application you are trying to use, and invokes the functions inside the app that you need.
IF that won't work for you, you could allow the window to be created, then instantly set your application to be the foreground window using:
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
public void ForceToFront()
{
SetForegroundWindow(Handle.ToInt32());
}
then you could send keys to the now background window using Win32 APIs. There's a pretty good (although fairly old) example here: http://www.codeproject.com/KB/cs/SendKeys.aspx
Related
I want to make a GUI Windows application that can run console applications. When this happens, the console window should not be shown. Instead its content should be shown in a visual component (memo/richedit). This component should show exactly the same content which would appear in the console window, even the color of the text and its background should be displayed. So this visual component should work exactly as a console window. I know that the standard output can be captured but many console applications do not use it. Is it possible to capture the output of a console application this way? Are there Windows API calls that can handle this?
I use Delphi XE2 but C# code would also be helpful.
You have to run the console mode program with stdout redirection to a pipe that your Delphi program will create. Your Delphi program can read the pipe to get the console mode program output and do whatever it needs to. By the way, this works not only with Delphi but also with any language able to create pipe and run program with I/O redirection.
If you need Delphi code to do that, have a look at this reference.
There is a ready-to-run component on GitHub: DosCommand
The Demo shows two ways how to do what you describe.
I am not sure if it works for older versions like XE2, but at least you can give it a try.
Traditionally you would call CreateProcess with stdin/stdout set to pipes you created. This should work for most programs but not for anything that uses a ncurses style "GUI" and you also lose the color information. An example can be found on MSDN.
Windows 10 (1809?) added support for pseudoconsoles. This is used by the new Terminal application and is your best bet for full console compatibility.
The last alternative is to inject into the child process and hook WriteFile, ReadFile and all the console functions but this is ugly and error-prone.
I've been thinking of giving the in Windows implemented cmd a fresh look and make a WinForm out of it(C# .net4.0 or later or latest mono# distribution).
Now, what I plan on doing is:
only showing the form, no console visible(even in the task bar)
telling the cmd what to do by virtually typing into it
catching the consoles output and using the form to make the user interact
I thought of some kind of "return" thing, like a dll would do, but I have not used consoles and forms together in a single project, so there's my question:
How do I not show a console window but write commands into it's line and receive the output with a WinForms application?
Thanks in advance.
--EDIT
I should maybe add that my main problem is typing catching the consoles output and also typing into it while it's not visible and thus not focusable.
You may well run into difficulties other than simply suppressing the appearance of a console window. But as far as that particular requirement goes, it's not hard.
You'll use the System.Diagnostics.Process class to start the process. Before starting the process, you'll need to see ProcessStartInfo.CreateNoWindow property to true. Note that you also need to set ProcessStartInfo.UseShellExecute to false, otherwise the CreateNoWindow property is ignored.
As for the broader problem: it seems likely that you'll need to start the console process using "cmd.exe /k" to instantiate a new command-line interpreter process without it exiting before you're done with it. Then you'll also need to use the redirection features in the Process class to read from stdout and stderr, and to write to stdin.
I've got a command line application that starts up and does some work. During that time, it listens to keystrokes (s => show status). It's not the typical command prompt where you press 's' and <ENTER> - it's the type which reacts as soon as the key is pressed the status is shown.
Now I'm trying to "control" that command line application from a fancy GUI application by sending keystrokes. I've tried the more conventional approach of writing to the Process' StandardInput but that doesn't seem to have an effect at all. Also, because the actual process doesn't have a window (it's started with CreateNoWindow=true) I can't try the Win32 API for sending keystrokes to a window.
Is there any other way of doing it?
Fancy console applications are problematic.
They have a tendency to directly read the keyboard input, instead of going through stdin. They also have a tendency to directly control their console, instead of going through stdout.
AFAIK, there is no way to programmatically control these apps. If you really, really need to, I would explore something like AutoHotKey controlling the app on a private desktop (AHK uses a virtual keyboard/mouse driver). I'm not sure how you would read the results off the console, though; it may be possible to create an intermediate console app that's started by your program (in the private desktop) and starts the target app. The intermediate app would then share its console with the target app and use low-level I/O to detect changes.
Or you could use Detours to bend the target app to your will.
Well, I seem to have found an answer to my own question.
It's a real "kludged together" solution, but it works - and for all the intents and purposes of the application I'm building, it doesn't matter.
So, what I did was use two WinAPI functions called
static extern bool ShowWindow(IntPtr WindowHandle, int nCmdShow);
static extern bool SetForegroundWindow(IntPtr WindowHandle);
The first one can be used to Show/Hide a window by changing nCmdShow to 1 and 0 respectively. The other one puts the window (determined by WindowHandle) to the front. Combining these two together, I was able to programmaticly bring the console window up front, do a simple SendKeys.Send(); operation and then hide it again.
// Use a WIN API command to bring the command line to front
SetForegroundWindow(workerProcess.MainWindowHandle);
// Send a keystore to re-display the STATUS of the worker
SendKeys.Send("s");
// Hide the window again.
ShowWindow(workerProcess.MainWindowHandle, 0);
Now, it's a real kludge job, but it gets the job done. One potential pitfall would be if a user is using the computer for something else, and would nail that 1 in a 10000000 moment when the window is active with a 'q' - it would quit the worker program. But the application is intended to be used on dedicated machines that most likely won't even have monitors, keyboards or mice attached to them so it wouldn't be an issue.
Thanks to all who answered, since you did - in one way or another, steer me towards the right solution.
I found an even better way to accomplish the functionality without the theoretical risk of causing problems with simultaneous user input and window-switching.
The trick is to use the WinAPI functions called PostMessage to send up KeyDown (or KeyUp) message to the process which does the same thing. No need to bring the process window to the front and hide it immediately afterwards!
I'm sending the key-down command with key 'S' as the argument:
// 0x0100 - VM_KEYDOWN
// 0x0101 - VM_KEYUP
// 0x53 - S-key
PostMessage(workerProcess.MainWindowHandle, 0x0100, 0x53, 0);
PostMessage(workerProcess.MainWindowHandle, 0x0101, 0x53, 0);
What is the best way to manage an external windows application in C# (or .NET)?
So far my I've been able to launch a process using System.Diagnostics.Process, however this simply allows me to launch/kill a process. (from what I've gathered)
I noticed System.Diagnostics.Process has a CloseMainWindow() routine which will send a request to a process' window. Can I use this Process class to send different messages? (if so, can anyone point me in direction of where I can learn about these windows messages)
I need to be able to manage an external program and manipulate it the following ways:
1) Launch
2) Kill Process
3) Show Application (Fullscreen and in taskbar)
4) Hide Application (Fullscreen and in taskbar)
Further details:
Windows 7, Restricted to .Net 3.5 Framework
You might be able to use interop and use SendMessage to do all of your functionality. See this: http://pinvoke.net/default.aspx/user32.SendMessage
Try sending a message to that window. Take a look at SendMessage . The messages you need are SW_MINIMIZE,SW_RESTORE and SW_SHOWMAXIMIZED.
You're going to need to use some Win32 P/Invoke stuff to send window messages in order to do what you want.
See this code sample on ShowWindow or SendMessage which tells an external window to show or hide itself. You'll first need to get the window handle you want with FindWindowEx.
you can do all you want in different ways, once you start the process yourself or you find it in the list of running processes, using classes or methods of System.Diagnostics.Process, then you can follow different options...
for example consider that once you have this handle: Process.MainWindowHandle you can send messages to that handle, with SendMessage and PostMessage and this allows you to do very very much; or you can use PInvoke APIs like SetWindowPos or ShowWindow or SetWindowLong and do basically really everything...
see this for example:
How to use the ShowWindow API to hide and show a form
I can send you more links but won't like to refer to the whole MSDN ;-)
I've read a few topics about programs that combine Windows Forms and console applications, but it seems my question hasn't been solved yet. Is it possible to run a program from cmd-line and to be able to control the application via forms and via cmd-line commands? It means:
for ordinary users of the application to control the application via (Windows Forms) forms,
for debugging and advanced users to control the application via the console (and optionally see what's happening in Windows Forms))
I know that what I want is quite a big deal, and it will probably mean a lot of work, but still I would like to know how to do it properly.
It isn't difficult, just P/Invoke the AllocConsole() API function to create your own console. For example, make your Program.cs source code file look like this:
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#if DEBUG
CreateConsole();
#endif
Application.Run(new Form1());
}
static void CreateConsole() {
var t = new System.Threading.Thread(() => {
AllocConsole();
for (; ; ) {
var cmd = Console.ReadLine();
if (cmd.ToLower() == "quit") break;
// Etc...
}
FreeConsole();
});
t.IsBackground = true;
t.Start();
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool FreeConsole();
}
You just need to start your Windows Forms application with an ApplicationContext instead of a form itself. You are then not depending on the main form to be shown and can act like an console application.
You could also just create a command-line executable and link with the Windows Forms libraries yourself to use them.
Another way would be to use some kind of starter, that fires up the Windows Forms application, and a command line tool that communicates with the Windows Forms application over local networking, or some other inter-process communication, D-Bus or similiar systems - many ways lead to Rome...
Yes, what you want is very possible. You have options. Some I can think of...:
Use UI Automation to write a controller application that can connect to the Windows Forms application and control it. This is new in Windows Vista. There are managed classes packaged in the System.Windows.Automation namespace, which first shipped in WPF, which arrived in .NET 3.0. (Now that I think about it, I'm not sure "new in Windows Vista" is true. It may be "new in .NET 3.0" which implies it also works on Windows XP. Hmmm....) UI Automation requires no code change to the Windows Forms application, but it can be sort of low-level, because you need to program each mouse click or cut/paste. See the answer to Stack Overflow question Is there a way to control a third-party EXE file from VB.NET?.
Modify your Windows Forms application to expose its function via a WM_COPYDATA interface. Then your client application can communicate with it. Again, the model here is two distinct applications, one of which can control or interrogate the other. The .NET Reflector tool is a good example of this approach. There's a ReflectorController, available as part of the ReflectorAddins project on CodePlex. The controller is a command-line tool, that can send WM_COPYDATA messages to Reflector, to tell it to open a new assembly, navigate to a particular class, and so on.
The code for the controller:
http://reflectoraddins.codeplex.com/sourcecontrol/network/Show?projectName=reflectoraddins&changeSetId=29526#19979
This approach will work for any Windows Forms application. You will need to override the WndProc method. To see how, check The Code Project article Use WM_COPYDATA to send data to/from C++ and C# Windows processes.
I also used this approach to build a Windows Forms-based progress monitor that can visually display the progress of long-running tests.
Within your application, expose a COM server object that can be programmed. This is exactly how Microsoft exposes Office function to applications. Office Automation allows any COM-capable program (C#, VBScript, PowerShell, Perl, PHP, etc.) to "drive" Office applications. The Office application is visible while that is happening. This approach would also require additional code in your Windows Forms application; specifically you have to host a COM object and hook it up to your UI layer. This may be preferable if you want maximum flexibility for superusers - they can write their own scripts to drive that component.
I'm sure there are other options.
I remember seeing IronPython being used in a demo controlling Windows Forms from Python's command line interface (IDLE).
Edit:
I could not find the original video but this one should show what is possible without too much effort. See this video and jump to 19:00.
This would be possible. You will have to look into threading the Windows Forms form, possibly with the use of a separate application domain within the same process. You might look into creating a proxy object (a kind of message class inheriting MarshalByRefObject).
Normally when looking at your application, you have an UI layer and a business layer (and a data layer, and who knows many more layers). You can think of the console client as an UI layer (with simple command inputs) and the Windows Forms client as another one.
Simply check at application startup for command-line arguments. If there are arguments specified, instantiate the simple console classes, otherwise instantiate the (probably more complex) Windows Forms classes.
If you want your changes to reflect in the Windows Forms application (while controlling it from the console application) setup your applications as much as you can with databinding. Let your business layer reflect what's actually going on in your application.