C# unmanaged code call not working: AddConsoleAlias - c#

I have the following code which keeps returning FALSE with a value of 8 from the GetLastError() call.
8 apparently is ERROR_NOT_ENOUGH_MEMORY.
I of course have enough memory, but the process doesn't think so, can anyone enlighten me as to what could be going wrong?
The code below is all I have except for the Forms objects declarations of course, but I guess there is no need to see this as I have 2 text boxes and 1 button.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AddConsoleAlias
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("kernel32", SetLastError = true)]
static extern bool AddConsoleAlias(string Source, string Target, string ExeName);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
private void btnAddAlias_Click(object sender, EventArgs e)
{
if (AddConsoleAlias(txbSource.Text, txbTarget.Text, "cmd.exe"))
{
MessageBox.Show("Success");
}
else
{
MessageBox.Show(String.Format("Problem occured - {0}", GetLastError()));
}
}
}
}

AddConsoleAlias defines console alias. You have Windows Forms application without opened console. Console should be allocated before AddConsoleAlias invoke. To do that you can use AllocConsole function.
C# binding for this function is:
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
Your modified code will look like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32", SetLastError = true)]
static extern bool AddConsoleAlias(string Source, string Target, string ExeName);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
private void btnAddAlias_Click(object sender, EventArgs e)
{
AllocConsole();
if (AddConsoleAlias(txbSource.Text, txbTarget.Text, "cmd.exe"))
{
MessageBox.Show("Success");
}
else
{
MessageBox.Show(String.Format("Problem occured - {0}", GetLastError()));
}
}
}

Related

trying to inject a library in my own program

I'm currently trying to inject a library into a program I made(for learning purpose, it's just curiosity). I think I managed to do it, but it seems the code i did is laking of entry point maybe ?
this is the code I wrote :
I used visual studio code to generate a kind of hello-world dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace InjectDll
{
public class Inject
{
[DllImport("kernel32")]
static extern bool AllocConsole();
public Inject()
{
AllocConsole();
Console.WriteLine("blablabla");
}
public string test()
{
AllocConsole();
return "dll is injected";
}
}
}
I then made a basic program I where wanted to test my injection =>
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace basicProgram
{
class Program
{
static void Main(string[] args)
{
while(true){
Thread.Sleep(1000);
Console.WriteLine("Hello world");
}
}
}
}
So now I have my dll and the program i wanted to try my injection.I just had to write the injector, and this is what I did =>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace injectorTest.Inject
{
public enum DllInjectionResult
{
DllNotFound,
GameProcessNotFound,
InjectionFailed,
Success
}
class Injector
{
static readonly IntPtr INTPTR_ZERO = (IntPtr)0;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
//[DllImport("InjectDll.dll", CallingConvention = CallingConvention.StdCall)]
private const string DLL_NAME = "hello.dll";
private Process myProcess;
private string myPath;
public Injector()
{
}
public Injector(Process myProcess)
{
this.myProcess = myProcess;
this.myPath = Path.GetDirectoryName(myProcess.MainModule.FileName);
}
private void checkDll()
{
if (!File.Exists(myPath + #"\hello.dll")) {
}
}
public DllInjectionResult inject()
{
if (!File.Exists(myPath + "\\hello.dll"))
{
return DllInjectionResult.DllNotFound;
}
Console.WriteLine("process id : " + myProcess.Id);
if (myProcess == null)
{
return DllInjectionResult.GameProcessNotFound;
}
if (!startInject((uint)myProcess.Id, myPath + "\\hello.dll"))
{
return DllInjectionResult.InjectionFailed;
}
return DllInjectionResult.Success;
}
private bool startInject(uint processId, string dllPath)
{
IntPtr handleProcess = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, processId);
if (handleProcess == INTPTR_ZERO)
{
return false;
}
IntPtr lpAddress = VirtualAllocEx(handleProcess, (IntPtr)null, (IntPtr)dllPath.Length, (0x1000 | 0x2000), 0X40);
Console.WriteLine("lpaddr: " + lpAddress);
if (lpAddress == INTPTR_ZERO)
{
return false;
}
byte[] bytes = Encoding.ASCII.GetBytes(dllPath);
if (WriteProcessMemory(handleProcess, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (lpLLAddress == INTPTR_ZERO)
{
return false;
}
var remoteThread = CreateRemoteThread(handleProcess, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null);
if (remoteThread == INTPTR_ZERO)
{
return false;
}
CloseHandle(handleProcess);
return true;
}
}
}
It doesn't seems to fail i can see via ida (watching the helloworld program i tried to inject) that LoadLibraryW is trigered when I launch my injector (I then can see the path of the dll injected but it doesn't seems to trigger smthg.
It seems like I missing something (like an entry point in my dll maybe ?).
A normal C/C++ DLL will have a DllMain which gets executed when LoadLibrary is called which then passes through to a switch statement, normally we put our code inside the DLL_PROCESS_ATTACH case which will get executed on injection.
This equivalent doesn't exist in C#/CLR but you can do something tricky to make the same effect by using static constructors.
Make a class and initialize an object of that class, this will in turn call the static constructor. Something like this:
class someClass
{
//Static constructor
static someClass()
{
Console.WriteLine("injected");
}
}

C#, Need help to seperate one beginner program

As beginner lesson I want to port this tutorial http://null-byte.wonderhowto.com/how-to/create-simple-hidden-console-keylogger-c-sharp-0132757/ to a Windows Form Application.
This should show a user what keys are pressed inside a label called 'lblMessage'.
I have separeted the code now into two pieces.
Form1.cs
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public GlobalKeyHook hook = new GlobalKeyHook();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Origin
// _hookID = SetHook(_proc);
hook._hookID = hook.SetHook(_proc);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Origin
// UnhookWindowsHookEx(_hookID);
hook.UnhookWindowsEx(_hookID);
}
}
}
GlobalKeyHook.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
namespace WindowsFormsApplication3
{
class GlobalKeyHook : Form
{
#region DLLs
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
#region Fields and delegation
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
public static IntPtr _hookID = IntPtr.Zero;
public delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
#endregion
public GlobalKeyHook()
{
IntPtr hookID = _hookID;
LowLevelKeyboardProc proc = _proc;
}
static Form form = new Form();
#region Methods
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
form.Text = vkCode.ToString();
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
public static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
#endregion
}
}
But I am not able to use the public static IntPtr _hookID, the method SetHook() or the DLL UnhookWindowsHookEx in the Form1 class. Is it not possible to use this "types" from another class?
Not sure this will solve all your problems but may help you avoid a few of them down the line.
If this is .net 4.0 or higher your SetWindowsHookEX() call will likely return 0 (it failed) because .net no longer emulates a native module for managed dlls. To fix this you can add a DllImport for LoadLibrary() like this:
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
Then somewhere before you call SetWindowsHookEX() do this:
IntPtr hinstDLL = UnsafeMethods.LoadLibrary("user32.dll");
and call SetWindowsHookEX() like this:
SetWindowsHookEx(WH_KEYBOARD_LL, proc,
hinstDLL, 0);
Basically SetWindowsHookEX() needs a valid module handle which it verifies but never actually uses it. the reason to load user32 is that since you are p/invoking functions from it you def have it.
Also, in your constructor just set it to IntPtr.Zero. No need make _hookID if you always are setting it to IntPtr.Zero. It is also worth noting that if the computer you are running this on has less than win7sp1 using IntPtr.Zero won't work (99% sure at least.)
I would strongly suggest you check out This set of hooks They have a decent implementation of a hook library that you can easily extend however you want.
You need to set your GlobalKeyHook class to public class GlobalKeyHook.

Cyclic sending of messages to different procces using SendMessage()

UPD: added MCVE.
This is an educational task. I have to use SendMessage() function:
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd,
uint wMsg, UIntPtr wParam, IntPtr lParam);
I have to make two different applications with GUI communicationg by messages. After getting message like "start" 1 app have to start sendinding message "Ask value" to 2 app each 5 seconds. And 2 app send to 1 app message "Send value" with some data.
1 app is WinForms program:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Oven_Monitor
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentProcessId();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
private uint askMessageID = RegisterWindowMessage("Ask value");
private uint dataMessageID = RegisterWindowMessage("Send value");
private uint registerMessageID = RegisterWindowMessage("Register sensor");
public Form1() {
InitializeComponent();
this.Text = "Really rare title";
}
public void checkSensors() {
while (true) {
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
System.Threading.Thread.Sleep(500);
}
}
private IntPtr secondAppHWnd;
protected override void WndProc(ref Message m) {
if (m.Msg == registerMessageID) {
secondAppHWnd = m.LParam;
Thread tr = new Thread(checkSensors);
tr.Start();
} else if (m.Msg == dataMessageID) {
//do some stuff
}
base.WndProc(ref m);
}
}
}
2 app is console project, but it requires System.Windows.Forms referens:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HeatSensor
{
class Program
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void Main(string[] args)
{
IntPtr mainAppHandle = FindWindow(null, "Really rare title");
while (mainAppHandle == IntPtr.Zero)
{
Console.ReadKey();
mainAppHandle = FindWindow(null, "Really rare title");
}
HiddenForm form = new HiddenForm(mainAppHandle);
while (true) //it's actually not infinit
{
//do some stuff
}
}
}
}
And hidden form class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HeatSensor
{
public partial class HiddenForm : Form
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
static private IntPtr mainAppHandle;
public HiddenForm(IntPtr mainAppHWnd)
{
InitializeComponent();
mainAppHandle = mainAppHWnd;
string title = System.DateTime.Now.ToLongDateString();
title += System.DateTime.Now.ToLongTimeString();
title += System.DateTime.Now.Ticks.ToString();
this.Text = title;
this.CreateHandle();
int currentWindowHandle = (int)FindWindow(null, title);
SendMessage(mainAppHandle, RegisterWindowMessage("Register sensor"),
(UIntPtr)0, currentWindowHandle);
}
private uint askMessageID = RegisterWindowMessage("Ask value");
private uint dataMessageID = RegisterWindowMessage("Send value");
private uint registerMessageID = RegisterWindowMessage("Register sensor");
protected override void WndProc(ref Message m)
{
if (m.Msg == askMessageID)
{
SendMessage(mainAppHandle, dataMessageID, (UIntPtr)1, (IntPtr)1);
}
base.WndProc(ref m);
}
}
}
For some reason this programs act strange. Almost everytime 2 app don't getting sended "Ask value" message, sometimes checkSensors() send 1-3 messages and stop.
What is wrong?
Both HWnd is correct.
Update: I tried to check error here:
public void checkSensors() {
while (true) {
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
int error = Marshal.GetLastWin32Error();
System.Threading.Thread.Sleep(500);
}
}
And see. As SendMessage was performed, this thread was blocked (what means, SendMessage was not copleted. After i closed 2 app, thread was unblocked and i got 164 error (ERROR_MAX_THRDS_REACHED: No more threads can be created in the system.). What it's supposed to mean?
Also, added:
protected override void WndProc(ref Message m)
{
//here is all message checks
int erro2r = Marshal.GetLastWin32Error();
if (erro2r != 0) {
int j; //stop to debug here
}
base.WndProc(ref m);
}
And it just constantly return 1400 ERROR_INVALID_WINDOW_HANDLE (i don't send any messages at that moment).
So it looks totaly unclear to me.
update 2: If i call it from WndProc(), everything works:
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
But i need to send this message from different thread each 5 seconds.
So, it finally works if both programs is WinForms projects. I can just run console window from 2 app and hide main window.

Getting infos out of an activex plugin in C#

I'm using the Sopcast activex plugin (sopocx.ocx) in one of my C# applications.
I would like to retrieve the player status ("Buffering the channel", "Playing the channel", "Channel Offline...") and the buffering percentage. Both of these informationss are displayed on the player (I tried to post a picture but I don't have enough reputation yet).
The problem is the Sopcast activex plugin doesn't provide any methods in order to retrieve these informations.
Does someone has any idea on how this could be done??
GetWindowText results in an empty string...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
IntPtr hwnd = sopcast.Handle;
StringBuilder lpString = new StringBuilder(256);
GetWindowText(hwnd, lpString, 256);
MessageBox.Show(lpString.ToString());
}
private void playToolStripMenuItem_Click(object sender, EventArgs e)
{
sopcast.SetSopAddress("sop://broker.sopcast.com:3912/123456789");
sopcast.SetChannelName("Channel");
sopcast.Play();
}
}
}
You can identify Id control and get text with api windows
here a code sample (replace notepad by your application name) the most important for you is to get from your application a way to get ID control of your ocx window
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Security;
namespace Application
{
public class Program
{
public static void Main ( )
{
IntPtr hwnd = UnsafeNativeMethods.FindWindow("Notepad", null);
StringBuilder stringBuilder = new StringBuilder(256);
UnsafeNativeMethods.GetWindowText(hwnd, stringBuilder, stringBuilder.Capacity);
Console.WriteLine(stringBuilder.ToString());
}
}
[SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int GetWindowText ( IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount );
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr FindWindow ( string lpClassName, string lpWindowName );
}
}
I download sopcast and try to get status using spy++:
As you see, caption is status not the channel...
so you can not get it easier
the handle you have catched is for the whole control
Sopcast draws the status text using DrawText (i found out using API Monitor http://www.rohitab.com/apimonitor). So there is no way of getting the text using conventional GetWindowText function or similar. I was able to obtain the text by hooking DrawText function. For .NET EasyHook will enable you to do this.
My scenario:
I have a winforms app that hosts the activex control and i want to obtain the status text.
public class hooklocal : EasyHook.IEntryPoint
{
[DllImport("user32.dll")]
static extern int DrawText(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat);
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet = CharSet.Auto,SetLastError = true)]
delegate int DDrawText(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat);
int DrawTextH(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat)
{
//lpString contains the status text
return DrawText(hDC, lpString, nCount, lpRect, uFormat);
}
public hooklocal()
{
try
{
var CreateHook = LocalHook.Create(
LocalHook.GetProcAddress("user32.dll", "DrawTextW"),
new DDrawText(DrawTextH),
this);
CreateHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
catch (Exception ExtInfo)
{
Debugger.Break();
}
}
}
To use, instantiate hooklocal class in a new thread at program startup.
EasyHook download
https://easyhook.github.io/downloads.html

Forms and Console

I'm Running a forms application and a console application in one application.
How can i run the forms application and keep the console closed until i click a button on the form?
You need to call a couple of win32app calls most specifically allocconsole. here is an msdn post with some sample code.
You'll need to do a little P/Invoke:
Add the appropriate methods:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using StackOverflow.Extensions;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32.SafeHandles;
namespace StackOverflow
{
public partial class FormMain : Form
{
[DllImport("kernel32.dll",
EntryPoint = "GetStdHandle",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
// Some constants
private const int STD_OUTPUT_HANDLE = -11;
private const int MY_CODE_PAGE = 437;
public FormMain()
{
InitializeComponent();
}
public void PrepareConsole()
{
AllocConsole();
IntPtr stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = System.Text.Encoding.GetEncoding(MY_CODE_PAGE);
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
}
private void button1_Click(object sender, EventArgs e)
{
// Console was not visible before this button click
Console.WriteLine("This text is written to the console that just popped up.");
MessageBox.Show("But we're still in a Windows Form application.");
}
}
}

Categories