Click here to Skip to main content
15,891,204 members
Please Sign up or sign in to vote.
2.00/5 (1 vote)
See more:
I was hoping to make a single executable that could run both from a console window and as a WPF based GUI application, selected by a call line switch. I can pick up call line switches for the GUI version, and if the "-cli" switch is set, I can prevent opening of the main window, but Console.WriteLine() seems to go straight into the bit sink.

I have tried various ways to get hold of a reference to the console from which the program was started, for use with Console.SetOut(), but without success.

How can I get hold of a ref to the console?

Or, is there another simple trick I can use for making a single GUI/CLI executable?
Posted
Comments
Sergey Alexandrovich Kryukov 6-Nov-12 15:47pm    
What is GUI/CLI executable? What "-cli" switch, of what program?! CLI executable (MSIL code) can be UI or not, console or not, and it can be both at the same time. I don't see what's the problem?

What do you mean by "hold on a ref to the console"? All console API is static, it does not need a ref. Want to output in console with WPF application? Just do it. Again, what's the problem?
--SA
Sergey Alexandrovich Kryukov 6-Nov-12 15:50pm    
Do you need to create a single application which executes like a WPF application and a console application at the same time? This way too easy -- you don't need to do anything special.

Do you want a single application which optionally executes as a WPF application or console application, but not both at the same time? This is pretty difficult. I would suggest a simple work-around: two tiny applications both using big shared library assemblies.

--SA
Sergey Alexandrovich Kryukov 6-Nov-12 16:56pm    
[OP commented:]

If I could only access the console window from which the application was started, using the Console.xxx() functions, that would be what I need.

What I want to do is having a WPF application MyApp that when started from the console:

C:> MyApp -someoption -someotheroption

starts the graphical user interface; this is straightforward. Then, if I add the -cli switch (or whatever I choose to call it),

C:> Myapp -cli -someoption -someotheroption

the handler for the application startup event selects NOT to create a main window (or any other window) an not to show it. Rather, all user interaction is handled through Console functions from the same command window where MyApp was started.

My startup event handler picks up "-cli"; if given it will suppress creation and opening of the main window. The only thing missing is that the Console.xxx() functions don't work. The streams associated with Console seems to be null. So I need to set them to something non-null, and that "something" should be the initiating command window.

Certainly, I can tell the users: "Here are two executables, start MyApp1.exe if you want to run a graphical user interface, but use MyApp2.exe if you want to run a command line interface!" I would much rather give them a single executable, telling: "Here is MyApp. By default, it uses a graphical user interface, but you may select a command line interface by specifying '-cli' on the command line."

Making two executables is of course a fallback solution, but if thre is a way to make Console.xxx() functions refer to the starting console window, I wouldn't need that!

I really don't understand why there is a problem at all. Were Console.xxx() functions supposed to operate on the console window from which MyApp is started (as I expected them to!)? Then, what could be the reason why I can't make them work?
Sergey Alexandrovich Kryukov 6-Nov-12 17:02pm    
I got it. If you explained it all in first place, it would be a pretty good question.
This is a problem because this is not how it works.

But first of all, please don't place posts like that as "solution". "Add your solution here" is reserved exclusively for the cases when you answer someone's question or provide some other kind of help in reply. If you post like that, may will down-vote such post, or report it for abuse...

--SA
Sergey Alexandrovich Kryukov 6-Nov-12 17:35pm    
Answered, please see...
--SA

1 solution

First of all, your "-cli" parameter would be just a bad name, because all .NET assemblies are always CLI, console, WPF, and all other application types, even mixed mode (managed + unmanaged).

Now, some background. The problem is that the console presence is something specified during compilation, not during run time. All compilers has such option in the command line, and in the project file, this is prescribed "Output type" in project properties. If you specify "Windows Application" console is not shown, and if you specify "Console Application", the console is show. Unfortunately, this is misleading, so way to many developers do not understand what really happens. A Windows application can be a console application. You you develop a WPF application and use the option "Console Application" at any time, your application will remain WPF application, and the console will be shown, additionally. "Console Application" does not mean "not Windows".

Moreover, if you develop non-console application, console is not shown, but it still exists as the API System.Console. You still can write in such console, but it's just not shown.

So, what to do with that? You can show both, but the only problematic thing is to remove console which is already created, due to the compilation option. By the way, it's not a problem to remove a WPF window and all related code. For this, you need to write the WPF the entry point with the Application explicitly. Normally, it's hidden, but you can find the sample code in your auto-generated code. When you get it, remove "app" nodes from the project and write normal, not auto-generated code with the explicit entry point (Main). Of course, for your purpose, you would need to create the instance of Application and run it under if block, depending of command line.

So, this part is easy. But in the opposite option, how to remove the console. This is such a bad thing, that I would not recommend you to do so at all. I really don't know a good method (even though it might exist, but I doubt it). But using some "dirty" method is easy. For example, you can remove or hide the Windows using Windows API:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ea8b0fd5-a660-46f9-9dcb-d525cc22dcbd[^].

I call this method "dirty", because it is too much Windows-specific. This way, you badly hurt potential platform compatibility of your code. Besides, finding a window by name… not reliable thing. However, this part can be fixed. In better code, you could use GetConsoleWindow, which would give you your console window, the one of the calling process. And then hide it. Please see:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683175%28v=vs.85%29.aspx[^].

The P/Invoke of that will be:
C#
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

const int SW_HIDE = 0;
const int SW_SHOW = 5;


So, this is already a solution, as I say, dirty, but only due to the need for P/Invoke, not just the pure .NET code.

So, I still invite you to think about a work-around. If you need just one application, you still can have it. As I say, develop two separate tiny applications based on big shared code base, one WPF, another one console. Name them differently, not *.EXE, to avoid running them by accident. Create another, third application with the command line. Depending on command line, execute one of those two using System.Diagnostics.Process.Start. Also not very elegant, but this is a clear .NET solution without P/Invoke. This is another solution which will work.

Now, a very fancy variant of the previous solution. Create two separate assemblies the way I described above. In the host application (third one), create a separate Application Domain and execute your application there.

So, that's all you can do, to best of my knowledge. What else? Yes, for command line parsing, you can use my easy-to-use library:
Enumeration-based Command Line Utility[^].

—SA
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900