对从中启动WPF应用程序的控制台的引用 [英] Reference to console from which WPF app was started

查看:161
本文介绍了对从中启动WPF应用程序的控制台的引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望制作一个既可以从控制台窗口运行又可以作为基于WPF的GUI应用程序运行的可执行文件,该应用程序是由呼叫线路开关选择的.我可以选择GUI版本的呼叫线路开关,并且如果设置了"-cli"开关,则可以防止打开主窗口,但是Console.WriteLine()似乎直接进入了位接收器. >
我尝试了各种方法来获取对从其启动程序的控制台的引用,以便与Console.SetOut()一起使用,但是没有成功.

如何获得对控制台的引用?

或者,还有另一个我可以用来制作单个GUI/CLI可执行文件的技巧吗?

解决方案

首先,您的"-cli"参数只是一个不好的名字,因为所有.NET程序集始终都是CLI,控制台,WPF和所有其他应用程序类型,甚至是混合模式(托管+非托管).

现在,有一些背景.问题在于控制台的存在是在编译过程中指定的,而不是在运行时指定的.所有编译器在命令行中都有这样的选项,并且在项目文件中,这在项目属性中指定为输出类型".如果指定"Windows应用程序"控制台,则不显示,如果指定控制台应用程序",则显示该控制台.不幸的是,这是一种误导,因此许多开发人员都不了解实际情况. Windows应用程序可以是控制台应用程序.您开发了WPF应用程序并在任何时候使用选项控制台应用程序",您的应用程序将仍然是WPF应用程序,并且将另外显示控制台. 控制台应用程序"并不表示不是Windows".

此外,如果您开发非控制台应用程序,则不会显示控制台,但它仍以API System.Console的形式存在.您仍然可以在这样的控制台中进行编写,但未显示.

那么,该怎么办呢?您可以同时显示两者,但是唯一的问题是由于编译选项而删除了已经创建的控制台.顺便说一句,删除WPF窗口和所有相关代码不是问题.为此,您需要使用Application显式地将WPF写入入口点.通常,它是隐藏的,但是您可以在自动生成的代码中找到示例代码.当您获得它时,请从项目中删除"app"节点,并使用显式入口点(Main)编写常规而非自动生成的代码.当然,出于您的目的,您需要创建Application的实例,并根据命令行在if块下运行它.

因此,这部分很容易.但是在相反的选择中,如何删除控制台.这是一件坏事,我根本不建议您这样做.我真的不知道一个好的方法(即使它可能存在,但我对此表示怀疑).但是使用一些肮脏"的方法很容易.例如,您可以使用Windows API删除或隐藏Windows:
http://social.msdn.microsoft.com/论坛/en-US/csharpgeneral/thread/ea8b0fd5-a660-46f9-9dcb-d525cc22dcbd [GetConsoleWindow,它将为您的控制台窗口提供调用过程之一.然后隐藏它.请参阅:
http://msdn.microsoft.com/zh-我们/library/windows/desktop/ms683175%28v=vs.85%29.aspx [ [DllImport(" )]] 静态 外部 IntPtr GetConsoleWindow(); [DllImport(" )] 静态 外部 布尔 ShowWindow( IntPtr hWnd, int nCmdShow); const int SW_HIDE = 0 ; 常量 int SW_SHOW = 5 ; pre>

因此,正如我所说,这已经是一个肮脏的解决方案,但这仅仅是由于需要P/Invoke,而不仅仅是纯粹的.NET代码.

因此,我仍然邀请您考虑解决方法.如果只需要一个应用程序,则仍然可以使用它.正如我所说,基于大型共享代码库开发两个单独的微型应用程序,一个是WPF,另一个是控制台.为它们命名不同,而不是* .EXE,以免意外运行它们.使用命令行创建另一个第三个应用程序.根据命令行,使用System.Diagnostics.Process.Start执行这两个命令之一.也不是很优雅,但这是没有P/Invoke的清晰.NET解决方案.这是另一个可行的解决方案.

现在,它是先前解决方案的一个非常精美的变体.按照上述方法创建两个单独的程序集.在宿主应用程序(第三个)中,创建一个单独的应用程序域并在其中执行您的应用程序.

因此,据我所知,这就是您所能做的.还有什么?是的,对于命令行解析,您可以使用我易于使用的库:
基于枚举的命令行实用程序 [
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?

解决方案

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:

[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


这篇关于对从中启动WPF应用程序的控制台的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆