Related to my earlier question:
I came up with the following approach, in which I created this WinForms control:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ConsoleWindow : Control
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private static ConsoleWindow _theWindow;
public ConsoleWindow()
{
if (!DesignMode)
{
if (_theWindow != null)
{
throw new Exception("An application can have only one ConsoleWindow");
}
_theWindow = this;
AllocConsole();
var newOut = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true };
Console.SetOut(newOut);
Console.SetError(newOut);
var consoleHwnd = GetConsoleWindow();
SizeChanged += (sender, args) =>
{
SetWindowPos(consoleHwnd, IntPtr.Zero, 0, 0, Width, Height, 0);
};
SetWindowLong(consoleHwnd, -16 /*GWL_STYLE*/, 0x50000000 /* WS_CHILD|WS_VISIBLE*/);
SetParent(consoleHwnd, Handle);
SetWindowPos(consoleHwnd, IntPtr.Zero, 0, 0, 0, 0, 0);
}
}
protected override void Dispose(bool disposing)
{
if (disposing && _theWindow != null)
{
FreeConsole();
_theWindow = null;
}
base.Dispose(disposing);
}
}
... which I can then use in my WPF application via XAML such as this:
<WindowsFormsHost>
<WindowsFormsHost.Child>
<controls:ConsoleWindow></controls:ConsoleWindow>
</WindowsFormsHost.Child>
</WindowsFormsHost>
It mostly works, except that mouse interaction seems impaired. When you create a console window (normally operates as a top-level window) you can use the mouse to click/drag an arbitrary selection, but this no longer works after parenting it as a child control as I have done. I can right-click to invoke the console window's context menu to select/copy all text, but I can't do a click/drag selection.
Is there a way to fix this (missing/incorrect styles or message routing perhaps?) so that I can interact with the console window as expected, or is there a fundamental problem with parenting the console window in this manner?
There is a control written by Dave Kerr which Solves Your problem.
Use this link: https://www.codeproject.com/articles/335909/embedding-a-console-in-a-c-application
this should be added that it uses a class named ProcessInterface which is included in the link.
and at last this part of code is the solution:
/// <summary>
/// Handles the KeyDown event of the richTextBoxConsole control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.Forms.KeyEventArgs"/> instance containing the event data.</param>
void richTextBoxConsole_KeyDown(object sender, KeyEventArgs e)
{
bool inReadOnlyZone = richTextBoxConsole.Selection.Start.CompareTo(inputStart) < 0;
// If we're at the input point and it's backspace, bail.
if (inReadOnlyZone && e.Key == Key.Back)
e.Handled = true;;
// Are we in the read-only zone?
if (inReadOnlyZone)
{
// Allow arrows and Ctrl-C.
if (!(e.Key == Key.Left ||
e.Key == Key.Right ||
e.Key == Key.Up ||
e.Key == Key.Down ||
(e.Key == Key.C && Keyboard.Modifiers.HasFlag(ModifierKeys.Control))))
{
e.Handled = true;
}
}
// Is it the return key?
if (e.Key == Key.Return)
{
// Get the input.
//todostring input = richTextBoxConsole.Text.Substring(inputStart, (richTextBoxConsole.SelectionStart) - inputStart);
// Write the input (without echoing).
//todoWriteInput(input, Colors.White, false);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With