Windows Forms + commands from the console in C#
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.
精彩评论