すぐに立ち往生するための非常に基本的な例:
using System;
using System.Windows.Forms;
class test
{
static void Main()
{
Console.WriteLine("test");
MessageBox.Show("test");
}
}
これをデフォルトのオプション(コマンドラインでcscを使用)でコンパイルすると、予想どおりにコンソールアプリケーションにコンパイルされます。また、System.Windows.Forms
をインポートしたため、メッセージボックスも表示されます。
ここで、オプション/target:winexe
を使用すると、プロジェクトオプション内からWindows Application
を選択するのと同じと思いますが、予想どおり、メッセージボックスのみが表示され、コンソール出力は表示されません。
(実際、コマンドラインから起動した瞬間に、アプリケーションが完了する前に次のコマンドを発行できます)。
だから、私の質問は-コンソールアプリケーションから「ウィンドウ」/フォームを出力できることを知っていますが、Windowsアプリケーションからコンソールを表示する方法はありますか?
これは動作するはずです。
using System.Runtime.InteropServices;
private void Form1_Load(object sender, EventArgs e)
{
AllocConsole();
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
おそらくこれは過度に単純すぎる...
Windows Formプロジェクトを作成...
次に、プロジェクトのプロパティ->アプリケーション->出力タイプ->コンソールアプリケーション
その後、コンソールとフォームを一緒に実行することができ、私のために働く
Pinvokeを使用してAttachConsole
を呼び出して、WinFormsプロジェクトに接続されたコンソールウィンドウを取得できます。 http://www.csharp411.com/console-output-from-winforms-application/
Log4net( http://logging.Apache.org/log4net/index.html )を考慮して、さまざまな構成でログ出力を構成することもできます。
これは、出力をファイルにパイプするのに役立ちました。コンソールを呼び出す
cmd/c "C:\ path\to\your\application.exe"> myfile.txt
このコードをアプリケーションに追加します。
[DllImport("kernel32.dll")]
static extern bool AttachConsole(UInt32 dwProcessId);
[DllImport("kernel32.dll")]
private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport("kernel32.dll")]
private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
[DllImport("kernel32.dll")]
private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
[DllImport("kernel32.dll")]
private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle, out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);
private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
private const UInt32 DUPLICATE_SAME_ACCESS = 2;
struct BY_HANDLE_FILE_INFORMATION
{
public UInt32 FileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
public UInt32 VolumeSerialNumber;
public UInt32 FileSizeHigh;
public UInt32 FileSizeLow;
public UInt32 NumberOfLinks;
public UInt32 FileIndexHigh;
public UInt32 FileIndexLow;
}
static void InitConsoleHandles()
{
SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup;
BY_HANDLE_FILE_INFORMATION bhfi;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
// Get current process handle
IntPtr hProcess = Process.GetCurrentProcess().Handle;
// Duplicate Stdout handle to save initial value
DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup,
0, true, DUPLICATE_SAME_ACCESS);
// Duplicate Stderr handle to save initial value
DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup,
0, true, DUPLICATE_SAME_ACCESS);
// Attach to console window – this may modify the standard handles
AttachConsole(ATTACH_PARENT_PROCESS);
// Adjust the standard handles
if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
}
else
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
}
if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
{
SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
}
else
{
SetStdHandle(STD_ERROR_HANDLE, hStdErr);
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
// initialize console handles
InitConsoleHandles();
if (args.Length != 0)
{
if (args[0].Equals("waitfordebugger"))
{
MessageBox.Show("Attach the debugger now");
}
if (args[0].Equals("version"))
{
String TypeOfBuild = "";
#if DEBUG
TypeOfBuild = "d";
#else
TypeOfBuild = "r";
#endif
String output = TypeOfBuild + Assembly.GetExecutingAssembly().GetName().Version.ToString();
//Just for the fun of it
Console.Write(output);
Console.Beep(4000, 100);
Console.Beep(2000, 100);
Console.Beep(1000, 100);
Console.Beep(8000, 100);
return;
}
}
}
ここでこのコードを見つけました: http://www.csharp411.com/console-output-from-winforms-application/ ここにも投稿する価値があると思った.
ここでは、基本的に2つのことが起こります。
コンソール出力winformsプログラムは、それを作成したコンソールウィンドウ(または別のコンソールウィンドウ、または必要に応じて実際に新しいコンソールウィンドウ)に自分自身をアタッチすることができます。コンソールウィンドウにアタッチすると、Console.WriteLine()などは正常に機能します。このアプローチの落とし穴の1つは、プログラムがすぐにコンソールウィンドウに制御を返し、書き込みを続行するため、ユーザーがコンソールウィンドウに入力することもできることです。これを処理するには、/ waitパラメーターを指定してstartを使用できます。
リダイレクトされたコンソール出力これは、誰かがあなたのプログラムからの出力をどこか他の場所にパイプするときです。
yourapp> file.txt
この場合、コンソールウィンドウにアタッチすると、パイピングは事実上無視されます。これを機能させるには、Console.OpenStandardOutput()を呼び出して、出力のパイプ先のストリームへのハンドルを取得します。これは、出力がパイプされる場合にのみ機能するため、両方のシナリオを処理する場合は、標準出力を開いて書き込み、コンソールウィンドウにアタッチする必要があります。これは、出力がコンソールウィンドウとパイプに送信されることを意味しますが、私が見つけることができる最良の解決策です。これを行うために使用するコードの下。
// This always writes to the parent console window and also to a redirected stdout if there is one.
// It would be better to do the relevant thing (eg write to the redirected file if there is one, otherwise
// write to the console) but it doesn't seem possible.
public class GUIConsoleWriter : IConsoleWriter
{
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
StreamWriter _stdOutWriter;
// this must be called early in the program
public GUIConsoleWriter()
{
// this needs to happen before attachconsole.
// If the output is not redirected we still get a valid stream but it doesn't appear to write anywhere
// I guess it probably does write somewhere, but nowhere I can find out about
var stdout = Console.OpenStandardOutput();
_stdOutWriter = new StreamWriter(stdout);
_stdOutWriter.AutoFlush = true;
AttachConsole(ATTACH_PARENT_PROCESS);
}
public void WriteLine(string line)
{
_stdOutWriter.WriteLine(line);
Console.WriteLine(line);
}
}
using System;
using System.Runtime.InteropServices;
namespace SomeProject
{
class GuiRedirect
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(StandardHandle nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetStdHandle(StandardHandle nStdHandle, IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern FileType GetFileType(IntPtr handle);
private enum StandardHandle : uint
{
Input = unchecked((uint)-10),
Output = unchecked((uint)-11),
Error = unchecked((uint)-12)
}
private enum FileType : uint
{
Unknown = 0x0000,
Disk = 0x0001,
Char = 0x0002,
Pipe = 0x0003
}
private static bool IsRedirected(IntPtr handle)
{
FileType fileType = GetFileType(handle);
return (fileType == FileType.Disk) || (fileType == FileType.Pipe);
}
public static void Redirect()
{
if (IsRedirected(GetStdHandle(StandardHandle.Output)))
{
var initialiseOut = Console.Out;
}
bool errorRedirected = IsRedirected(GetStdHandle(StandardHandle.Error));
if (errorRedirected)
{
var initialiseError = Console.Error;
}
AttachConsole(-1);
if (!errorRedirected)
SetStdHandle(StandardHandle.Error, GetStdHandle(StandardHandle.Output));
}
}
//From your application set the Console to write to your RichTextkBox
//object:
Console.SetOut(new RichTextBoxWriter(yourRichTextBox));
//To ensure that your RichTextBox object is scrolled down when its text is
//changed add this event:
private void yourRichTextBox_TextChanged(object sender, EventArgs e)
{
yourRichTextBox.SelectionStart = yourRichTextBox.Text.Length;
yourRichTextBox.ScrollToCaret();
}
public delegate void StringArgReturningVoidDelegate(string text);
public class RichTextBoxWriter : TextWriter
{
private readonly RichTextBox _richTextBox;
public RichTextBoxWriter(RichTextBox richTexttbox)
{
_richTextBox = richTexttbox;
}
public override void Write(char value)
{
SetText(value.ToString());
}
public override void Write(string value)
{
SetText(value);
}
public override void WriteLine(char value)
{
SetText(value + Environment.NewLine);
}
public override void WriteLine(string value)
{
SetText(value + Environment.NewLine);
}
public override Encoding Encoding => Encoding.ASCII;
//Write to your UI object in thread safe way:
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (_richTextBox.InvokeRequired)
{
var d = new StringArgReturningVoidDelegate(SetText);
_richTextBox.Invoke(d, text);
}
else
{
_richTextBox.Text += text;
}
}
}
アプリケーションの種類をコンソールまたはウィンドウにいつでも切り替えることができます。そのため、stdoutを表示するための特別なロジックは作成しません。また、デバッガーでアプリケーションを実行すると、出力ウィンドウにすべての標準出力が表示されます。また、単にブレークポイントを追加するだけで、ブレークポイントプロパティが「ヒット時...」に変更されると、メッセージと変数を出力できます。また、「Continue execution」をオン/オフにすると、ブレークポイントが正方形になります。したがって、デバッグ出力ウィンドウでは、アプリケーション内の何も変更せずにブレークポイントメッセージが表示されます。
Window Formsアプリとしてそのままにして、コンソールを模倣するシンプルなフォームを作成してみませんか。フォームは、ブラックスクリーンのコンソールのように見えるようにし、キーを押したときに直接応答するようにできます。次に、program.csファイルで、メインフォームまたはConsoleFormを実行する必要があるかどうかを決定します。たとえば、このアプローチを使用して、program.csファイル内のコマンドライン引数をキャプチャします。 ConsoleFormを作成し、最初に非表示にしてから、コマンドライン文字列をその中のAddCommand関数に渡します。これにより、許可されたコマンドが表示されます。最後に、ユーザーが-hまたは-?を指定した場合コマンド、ConsoleFormで.Showを呼び出し、ユーザーがキーを押すと、プログラムをシャットダウンします。ユーザーが-を与えない場合コマンド、非表示のConsoleFormを閉じてメインフォームを実行します。