Get the handle and write to the console that launched our process - c#

How could I write to the standard output of some already open console?
I find the console I need with this piece of code:
IntPtr ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
Process process = Process.GetProcessById(u);
The problem is how to get the standard output handle pointer (stdHandle) of this process.
I would then want something like:
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = Encoding.ASCII;
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
Code in C++ using windows API is OK - I can use pInvoke.
Effectively what I would like is to write text to an already open console window not spawned by my process (and it is the one that was in foreground when launching my process through command line - but my process is a WinApp so the console does not attach the std).
Can the standard output be redirected after the process has been created?
PS: I read about some COM file that can be used to do this, so this means that there is a programmatic way ...
Thanks!

I finally figured out how to attach transparently to a console if it is the foreground window while launching the windows app.
Don't ask me why STD_ERROR_HANDLE must be passed instead of STD_OUTPUT_HANDLE, but it simply works, probably because the standard error can be shared.
N.B.: the console can accept user input while displaying you app messages inside, but it is a bit confusing to use it while the stderr is outputting from you app.
With this snippet of code if you launch you app from a console window with at least one parameter it will attach Console.Write to it, and if you launch the app with the parameter /debug then it will attach even the Debug.Write to the console.
Call Cleanup() before exiting you app to free the console and send an Enter keypress to release the last line so the console is usable as before starting the app.
PS. You cannto use output redirection with this method ie.: yourapp.exe > file.txt because
you will get an empty file. And dont even try myapp.exe > file.txt 2>&1 because you will crash the app (redirecting error to output means we are trying to attach to a nonshared buffer).
Here is the code:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("kernel32.dll",
EntryPoint = "GetStdHandle",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
private static bool _consoleAttached = false;
private static IntPtr consoleWindow;
[STAThread]
static void Main()
{
args = new List<string>(Environment.GetCommandLineArgs());
int prId;
consoleWindow = GetForegroundWindow();
GetWindowThreadProcessId(consoleWindow, out prId);
Process process = Process.GetProcessById(prId);
if (args.Count > 1 && process.ProcessName == "cmd")
{
if (AttachConsole((uint)prId)) {
_consoleAttached = true;
IntPtr stdHandle = GetStdHandle(STD_ERROR_HANDLE); // must be error dunno why
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = Encoding.ASCII;
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
if (args.Contains("/debug")) Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
Console.WriteLine(Application.ProductName + " was launched from a console window and will redirect output to it.");
}
}
// ... do whatever, use console.writeline or debug.writeline
// if you started the app with /debug from a console
Cleanup();
}
private static void Cleanup() {
try
{
if (_consoleAttached)
{
SetForegroundWindow(consoleWindow);
SendKeys.SendWait("{ENTER}");
FreeConsole();
}
}
}

If the intention is to write to the parent console, if any, you can use the AttachConsole function with the ATTACH_PARENT_PROCESS argument. (see msdn attachconsole)
ATTACH_PARENT_PROCESS (DWORD)-1 : Use the console of the parent of the current process
And if you do need to check the parent process, you might use the CreateToolhelp32Snapshot and get the parent process thru the th32ParentProcessID member of the PROCESSENTRY32 structure.

If you just want to write to the console that's used by some other app, then you can use the following - you'll need to use P/Invoke to do the first step:
AttachConsole(pid) to attach to that console - if your process is already associated with a console, you'll have to FreeConsole first, since a process can be associated with only one console at a time.
Now that you're attached, get the console output handle using CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, ... ) - might be able to do this part in managed code.
Now that you've got the HANDLE, wrap it up in managed code - this part you already know.
Having said that, even though you can do this, it's not necessarily a good idea to do so. There's nothing to stop the original process from writing to the console while you are doing likewise, and the output from both getting mixed-up, depending on how the processes are doing buffering. If you want to do something like notify the user of something regardless of which window is active, there may be a better way of doing that.

A system process is uniquely identified on the system by its process identifier. Like many Windows resources, a process is also identified by its handle, which might not be unique on the computer. A handle is the generic term for an identifier of a resource. The operating system persists the process handle, which is accessed through the Process.Handle property of the Process component, even when the process has exited. Thus, you can get the process's administrative information, such as the Process.ExitCode (usually either zero for success or a nonzero error code) and the Process.ExitTime. Handles are an extremely valuable resource, so leaking handles is more virulent than leaking memory.
This is not the exact answer to ur questions , but it helps u to understand the basic thing actually.

Related

Process not suspending (NtSuspendProcess) -> What is going on?

I have adapted a 32-bit memory scanner in C# to 64-bit. Before scanning a program (read: live program), it is supposed to suspend the process. I am using NtSuspendProcess at this point to attempt to achieve this end. The funny thing is, I have this program (do not have access to the source) which, once a file is opened, refuses to suspend. Figuring it was a bug in my scanner, I tried suspending the program, once again when a file is opened, using Process Explorer; it flashes "Suspended" very briefly; I looked under Suspend Count for the threads associated with the process, and it increments just fine when I tell Process Explorer to suspend it...but when I tell Process Explorer to resume the process, it increments the Suspend Count (you read that right, it INCREMENTS it).
So yes, with my memory scanner and Process Explorer, when this program has no files open, it suspends and resumes normally. When the program has a file open, it fails to suspend, and increments the Suspend Count on attempts to resume.
I suspect a number of things here. Somehow, the message to suspend is being duplicated, and being released when resume is called. This explains the Suspend Count incrementing when it should be decrementing. Which might mean the original Suspend message isn't being consumed properly.
How do I even go about debugging this problem from this point? Where do I start?
Below are some code snippets from my memory scanner:
const uint PROCESS_SUSPEND_RESUME = 0x0800;
const uint PROCESS_QUERY_INFORMATION = 0x0400;
const uint MEM_COMMIT = 0x00001000;
const uint PAGE_READWRITE = 0x04;
const uint PROCESS_WM_READ = 0x0010;
[DllImport("ntdll.dll", EntryPoint = "NtSuspendProcess", SetLastError = true, ExactSpelling = false)]
private static extern UIntPtr NtSuspendProcess(UIntPtr processHandle);
[DllImport("ntdll.dll", EntryPoint = "NtResumeProcess", SetLastError = true, ExactSpelling = false)]
private static extern UIntPtr NtResumeProcess(UIntPtr processHandle);
[DllImport("kernel32.dll")]
public static extern UIntPtr OpenProcess(UIntPtr dwDesiredAccess, bool bInheritHandle, UIntPtr dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(UIntPtr hProcess, UIntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr dwSize, out UIntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);
[DllImport("kernel32.dll", SetLastError = true)]
static extern UIntPtr VirtualQueryEx(UIntPtr hProcess, UIntPtr lpAddress, out MEMORY_BASIC_INFORMATION64 lpBuffer, UIntPtr dwLength);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(UIntPtr hObject);
private void Button_Extract_Click(object sender, EventArgs e)
{
Process process = Process.GetProcessById(int.Parse(DataGridView_Processes.SelectedRows[0].Cells["Process ID"].Value.ToString()));
UIntPtr processSuspendResumeHandle = OpenProcess(new UIntPtr(PROCESS_SUSPEND_RESUME), false, new UIntPtr((uint)process.Id));
//process.Suspend();
UIntPtr suspendreturnvalue = NtSuspendProcess(processSuspendResumeHandle);
System.Diagnostics.Debug.WriteLine("Return Value: " + suspendreturnvalue.ToString());
UIntPtr processHandle = OpenProcess(new UIntPtr(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ), false, new UIntPtr((uint)process.Id));
//int error = Marshal.GetLastWin32Error();
//System.Diagnostics.Debug.WriteLine("Last Win32 Error: " + error);
SYSTEM_INFO sys_info = new SYSTEM_INFO();
GetSystemInfo(out sys_info);
UIntPtr proc_min_address = sys_info.minimumApplicationAddress;
UIntPtr proc_max_address = sys_info.maximumApplicationAddress;
ulong proc_min_address_l = (ulong)proc_min_address;
ulong proc_max_address_l = (ulong)proc_max_address;
//Skip to end
CloseHandle(processHandle);
NtResumeProcess(processSuspendResumeHandle);
CloseHandle(processSuspendResumeHandle);
MessageBox.Show("Extraction Complete.");
}
Do the following:
Make sure you are running as an admin
Check the return code of OpenProcess it should return a nonzero, if not continue to step 3.
Check the return code of GetLastError, search its value here https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- (this only contains error 0-400 so check the sidebar, there's a link to the other pages that contain other error codes)
Check the returned value of NtSuspendProcess and search it on the link above.
Since it looks like you're accessing the memory, you're probably using this app for game cheats.... so check OpenProcess, NtOpenProcess, NtSuspendProcess, and NtResumeProcess using an assembler such as Cheat Engine or x64dbg.
Go to the address of the functions I highlighted. Check if the first 5 bytes have a JMP instruction. If it has then that means the function has been patched by either an antivirus or an anticheat.
If it's patched, you might wanna disable the antivirus and if its still patched then you're against an anticheat. Switch to C++, use direct syscalls using syswhispers2, use Qt for C++ its a much better alternative to C# Winforms, it has a drag-and-drop form builder too.
If there is nothing suspicious, the functions didn't look patched. The GetLastError calls return normal status. Then you might be against a rootkit anticheat. In that case, you'll have to write your own driver to handle the open process, read memory, and write memory using C++ and WDK. You'll also need to find a mapper for your unsigned driver (KDMapper, LPMapper, etc) since it's not possible to load unsigned driver in the OS without disabling Driver Signature Enforcement feature of Windows, which when disabled, can be detected by an anti cheat.
EDIT:
I found this article about NtSuspendProcess failing when opening a process with PROCESS_SUSPEND_RESUME access mask. Try using PROCESS_ALL_ACCESS access mask instead.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e119f8e8-98bc-466e-a9bb-88bcbde6524c/why-does-ntsuspendprocess-fail-with-processsuspendresume-but-succeeds-with-processallaccess?forum=windowssdk

How do I echo into an existing CMD window

So the program I'm working on can be launched using command lines in CMD using the following code.
string[] commandLines = Environment.GetCommandLineArgs();
However I want to be able to return a message to the CMD window where the command lines came from after handling them. Any help would be appreciated.
Edit: I'm running the program as a Windows Application, not a console application.
I ended up solving the problem by using one of the answers RenniePet posted as a comment to my question. I'll list the solution down here for anyone trying to reproduce it.
[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 void 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)
{
GUIConsoleWriter();
_stdOutWriter.WriteLine(line);
Console.WriteLine(line);
}
After you've added this code to your program you can simply start returning lines by using, for example, the following.
WriteLine("\nExecuting commands.");
You can use the .NET SendKeys class to send keystrokes to an application you do not own. The target application must be active to be able to retrieve the keystrokes. Therefore before sending you have to activate your target application. You do so by getting a handle of the window and pinvoking into SetForegroundWindow with your handle.
Here is some example code to get you started:
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lp1, string lp2);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
IntPtr handle = FindWindow("ConsoleWindowClass", "Eingabeaufforderung");
if (!handle.Equals(IntPtr.Zero))
{
if (SetForegroundWindow(handle))
{
// send
SendKeys.Send("Greetings from Postlagerkarte!");
// send key "Enter"
SendKeys.Send("{ENTER}");
}
}
}
You want to use the Console class to interface with it if running a console application.
Console.WriteLine("Text");
If you are running a windows form application read here.

Starting process and storing handle to window

Would someone mind helping me out with a problem I've been stuck on for a bit? I'm using C# and trying to start a couple processes, and later move those windows to separate monitors.
So far this was the main idea:
Process p1 = Process.Start(#"1.pptx");
Process p2 = Process.Start(#"2.pptx");
SetWindowPos(p1.MainWindowHandle, -1,
0,
0,
100,
100,
SWP_SHOWWINDOW);
SetWindowPos(p2.MainWindowHandle, -1,
200,
200,
100,
100,
SWP_SHOWWINDOW);
But after trying a bunch of different things, I haven't been able to get it to work. Could anyone give me some pointers?
As a side note which is confusing me, if I print those to process IDs (p1, p2), and then run this code:
Process[] processlist = Process.GetProcesses();
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
Console.WriteLine("Process: {0} ID: {1} Window title: {2}", process.ProcessName, process.Id, process.MainWindowTitle);
}
}
those process IDs don't exist. I know there must be something simple I'm missing...?
UPDATE: The reason for the problem above is that for some reason the MainWindowTitle didn't have a value, so it wasn't printing the pid.
When you use Process.Start to open a document this is handled by the shell. The shell looks in the file association registry and takes whatever steps are needed to open the document.
This may involve creating a new process but equally may not. Office applications will typically reuse already open processes to open new documents. That's what is happening here.
And when this does happen, when no new process is started, the shell returns 0 for the new process handle. That's reflected back to the .net Process object. It explains why you have no main window handle.
So fundamentally your basic approach is flawed. Using Process.Start will not yield window handles for these documents. You'll have to find another way to locate these windows. For instance EnumWindows or a CBT hook. Or perhaps COM automation is the right solution.
As an aside it seems that you did not check for errors when you called SetWindowPos. That would have helped you work this out more quickly. Always check return values when calling Win32 functions.
For those who are still looking for an answer, this is what I did to get it working.
First, use EnumWindows to get a handle to each open window before starting any new process. Then start your process, then check all windows again making sure they're visible and have window text. If you have only 1 new process, chances are that's your new window. If not, I've tried it 3 times before failing. So far, the code has worked great.
Here is the code for helper functions/Win32 API calls.
public delegate bool EnumedWindow(IntPtr handleWindow, ArrayList handles);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ArrayList lParam);
public static ArrayList GetWindows()
{
ArrayList windowHandles = new ArrayList();
EnumedWindow callBackPtr = GetWindowHandle;
EnumWindows(callBackPtr, windowHandles);
return windowHandles;
}
private static bool GetWindowHandle(IntPtr windowHandle, ArrayList windowHandles)
{
windowHandles.Add(windowHandle);
return true;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
const int SWP_SHOWWINDOW = 0x0040;
[DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)]
public static extern Boolean SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
My main logic then went something like this (adjust as necessary):
List<IntPtr> alreadyOpenWindows = new List<IntPtr>();
foreach (IntPtr ip in GetWindows())
{
alreadyOpenWindows.Add(ip);
}
Process.Start("your command here");
System.Threading.Thread.Sleep(1000);
foreach (IntPtr ip in GetWindows())
{
// To consider it a new window, it must be visible, it must not have been open previously, and it must have window text length > 0
if (IsWindowVisible(ip) && alreadyOpenWindows.Contains(ip) == false)
{
StringBuilder windowText = new StringBuilder();
windowText.Length = 256;
GetWindowText(ip, windowText, windowText.Length);
if (windowText.Length > 0)
{
numNewWindows++;
handle = ip;
// break if your confident there will only be one new window opened
}
}
}
// Check numNewWindows if you'd like
if (handle != IntPtr.Zero)
{
SetWindowPos(handle, -1,
this.GetScreen().WorkingArea.X,
this.GetScreen().WorkingArea.Y,
this.GetScreen().WorkingArea.Width,
this.GetScreen().WorkingArea.Height,
SWP_SHOWWINDOW);
}

compare a string against a process name

i want to do this... IF notepad is in the foreground it opens the calculator... if another program is open does nothing... the notepad is oepn manualy... "Start, Notepad"... i have this code to "see" if notepad is open... dont know how to continue D: i know i have to use
if (switch == 0)
{
if (SOMETHING == "Notepad")
{
var switch = 1 //so it doesnt enters in a loop
OPEN CALCULATOR //irrelevant, i may use another part of otrher code that is already working
}
}
the "switch" variable is going to be 0 from the beginning of the code, so that is going to work (hope)
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
Process GetActiveProcess()
{
IntPtr hwnd = GetForegroundWindow();
uint pid;
GetWindowThreadProcessId(hwnd, out pid);
Process p = Process.GetProcessById((int)pid);
return p;
}
the problem is that i dont know what to put on "SOMETHING" to use the rest of the code, and Where or How to use the If...
You can do:
Process[] notePadProcesses = Process.GetProcessesByName("notepad.exe");
IntPtr activeWindowHandle = GetForegroundWindow();
if (notePadProcesses != null && notePadProcesses.Length > 0
&& notePadProcesses.Any(p=>p.MainWindowHandle == activeWindowHandle))
{
// notepad is open in the foreground.
switch = 1;
// OPEN Calculator or whatever you need to.
}
else
{
// notepad is either not open, or not open in the foreground.
}
basically we use the C# friendly Process class to find all the open notepad processes.
Then find if it is an active process and go from there.
please be careful using activewindow logic, because many a time, they result in race conditions where by the time you determine a process is active and try to do something, it may no longer be an active process. tread carefully.

Show Console in Windows Application?

Is there a way to show the console in a Windows application?
I want to do something like this:
static class Program
{
[STAThread]
static void Main(string[] args) {
bool consoleMode = Boolean.Parse(args[0]);
if (consoleMode) {
Console.WriteLine("consolemode started");
// ...
} else {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
What you want to do is not possible in a sane way. There was a similar question so look at the answers.
Then there's also an insane approach (site down - backup available here.) written by Jeffrey Knight:
Question: How do I create an application that can run in either GUI
(windows) mode or command line / console mode?
On the surface of it, this would seem easy: you create a Console
application, add a windows form to it, and you're off and running.
However, there's a problem:
Problem: If you run in GUI mode, you end up with both a window and a
pesky console lurking in the background, and you don't have any way to
hide it.
What people seem to want is a true amphibian application that can run
smoothly in either mode.
If you break it down, there are actually four use cases here:
User starts application from existing cmd window, and runs in GUI mode
User double clicks to start application, and runs in GUI mode
User starts application from existing cmd window, and runs in command mode
User double clicks to start application, and runs in command mode.
I'm posting the code to do this, but with a caveat.
I actually think this sort of approach will run you into a lot more
trouble down the road than it's worth. For example, you'll have to
have two different UIs' -- one for the GUI and one for the command /
shell. You're going to have to build some strange central logic
engine that abstracts from GUI vs. command line, and it's just going
to get weird. If it were me, I'd step back and think about how this
will be used in practice, and whether this sort of mode-switching is
worth the work. Thus, unless some special case called for it, I
wouldn't use this code myself, because as soon as I run into
situations where I need API calls to get something done, I tend to
stop and ask myself "am I overcomplicating things?".
Output type=Windows Application
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Microsoft.Win32;
namespace WindowsApplication
{
static class Program
{
/*
DEMO CODE ONLY: In general, this approach calls for re-thinking
your architecture!
There are 4 possible ways this can run:
1) User starts application from existing cmd window, and runs in GUI mode
2) User double clicks to start application, and runs in GUI mode
3) User starts applicaiton from existing cmd window, and runs in command mode
4) User double clicks to start application, and runs in command mode.
To run in console mode, start a cmd shell and enter:
c:\path\to\Debug\dir\WindowsApplication.exe console
To run in gui mode, EITHER just double click the exe, OR start it from the cmd prompt with:
c:\path\to\Debug\dir\WindowsApplication.exe (or pass the "gui" argument).
To start in command mode from a double click, change the default below to "console".
In practice, I'm not even sure how the console vs gui mode distinction would be made from a
double click...
string mode = args.Length > 0 ? args[0] : "console"; //default to console
*/
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(int dwProcessId);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[STAThread]
static void Main(string[] args)
{
//TODO: better handling of command args, (handle help (--help /?) etc.)
string mode = args.Length > 0 ? args[0] : "gui"; //default to gui
if (mode == "gui")
{
MessageBox.Show("Welcome to GUI mode");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else if (mode == "console")
{
//Get a pointer to the forground window. The idea here is that
//IF the user is starting our application from an existing console
//shell, that shell will be the uppermost window. We'll get it
//and attach to it
IntPtr ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
Process process = Process.GetProcessById(u);
if (process.ProcessName == "cmd" ) //Is the uppermost window a cmd process?
{
AttachConsole(process.Id);
//we have a console to attach to ..
Console.WriteLine("hello. It looks like you started me from an existing console.");
}
else
{
//no console AND we're in console mode ... create a new console.
AllocConsole();
Console.WriteLine(#"hello. It looks like you double clicked me to start
AND you want console mode. Here's a new console.");
Console.WriteLine("press any key to continue ...");
Console.ReadLine();
}
FreeConsole();
}
}
}
}
This is a tad old (OK, it's VERY old), but I'm doing the exact same thing right now. Here's a very simple solution that's working for me:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[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;
public static void ShowConsoleWindow()
{
var handle = GetConsoleWindow();
if (handle == IntPtr.Zero)
{
AllocConsole();
}
else
{
ShowWindow(handle, SW_SHOW);
}
}
public static void HideConsoleWindow()
{
var handle = GetConsoleWindow();
ShowWindow(handle, SW_HIDE);
}
Easiest way is to start a WinForms application, go to settings and change the type to a console application.
Disclaimer
There is a way to achieve this which is quite simple, but I wouldn't suggest it is a good approach for an app you are going to let other people see. But if you had some developer need to show the console and windows forms at the same time, it can be done quite easily.
This method also supports showing only the Console window, but does not support showing only the Windows Form - i.e. the Console will always be shown. You can only interact (i.e. receive data - Console.ReadLine(), Console.Read()) with the console window if you do not show the windows forms; output to Console - Console.WriteLine() - works in both modes.
This is provided as is; no guarantees this won't do something horrible later on, but it does work.
Project steps
Start from a standard Console Application.
Mark the Main method as [STAThread]
Add a reference in your project to System.Windows.Forms
Add a Windows Form to your project.
Add the standard Windows start code to your Main method:
End Result
You will have an application that shows the Console and optionally windows forms.
Sample Code
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ConsoleApplication9 {
class Program {
[STAThread]
static void Main(string[] args) {
if (args.Length > 0 && args[0] == "console") {
Console.WriteLine("Hello world!");
Console.ReadLine();
}
else {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
}
Form1.cs
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;
namespace ConsoleApplication9 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Click(object sender, EventArgs e) {
Console.WriteLine("Clicked");
}
}
}
Resurrecting a very old thread yet again, since none of the answers here worked very well for me.
I found a simple way that seems pretty robust and simple. It worked for me. The idea:
Compile your project as a Windows Application. There might be a parent console when your executable starts, but maybe not. The goal is to re-use the existing console if one exists, or create a new one if not.
AttachConsole(-1) will look for the console of the parent process. If there is one, it attaches to it and you're finished. (I tried this and it worked properly when calling my application from cmd)
If AttachConsole returned false, there is no parent console. Create one with AllocConsole.
Example:
static class Program
{
[DllImport( "kernel32.dll", SetLastError = true )]
static extern bool AllocConsole();
[DllImport( "kernel32", SetLastError = true )]
static extern bool AttachConsole( int dwProcessId );
static void Main(string[] args)
{
bool consoleMode = Boolean.Parse(args[0]);
if (consoleMode)
{
if (!AttachConsole(-1))
AllocConsole();
Console.WriteLine("consolemode started");
// ...
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
A word of caution : it seems that if you try writing to the console prior to attaching or allocing a console, this approach doesn't work. My guess is the first time you call Console.Write/WriteLine, if there isn't already a console then Windows automatically creates a hidden console somewhere for you. (So perhaps Anthony's ShowConsoleWindow answer is better after you've already written to the console, and my answer is better if you've not yet written to the console). The important thing to note is that this doesn't work:
static void Main(string[] args)
{
Console.WriteLine("Welcome to the program"); //< this ruins everything
bool consoleMode = Boolean.Parse(args[0]);
if (consoleMode)
{
if (!AttachConsole(-1))
AllocConsole();
Console.WriteLine("consolemode started"); //< this doesn't get displayed on the parent console
// ...
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
What worked for me was to write a console app separately that did what I wanted it to do, compile it down to an exe, and then do Process.Start("MyConsoleapp.exe","Arguments")
Check this source code out. All commented code – used to create a console in a Windows app. Uncommented – to hide the console in a console app. From here. (Previously here.) Project reg2run.
// Copyright (C) 2005-2015 Alexander Batishchev (abatishchev at gmail.com)
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace Reg2Run
{
static class ManualConsole
{
#region DllImport
/*
[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 CloseHandle(IntPtr handle);
/*
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPStr)]string fileName, [MarshalAs(UnmanagedType.I4)]int desiredAccess, [MarshalAs(UnmanagedType.I4)]int shareMode, IntPtr securityAttributes, [MarshalAs(UnmanagedType.I4)]int creationDisposition, [MarshalAs(UnmanagedType.I4)]int flagsAndAttributes, IntPtr templateFile);
*/
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern IntPtr GetStdHandle([MarshalAs(UnmanagedType.I4)]int nStdHandle);
/*
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetStdHandle(int nStdHandle, IntPtr handle);
*/
#endregion
#region Methods
/*
public static void Create()
{
var ptr = GetStdHandle(-11);
if (!AllocConsole())
{
throw new Win32Exception("AllocConsole");
}
ptr = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
if (!SetStdHandle(-11, ptr))
{
throw new Win32Exception("SetStdHandle");
}
var newOut = new StreamWriter(Console.OpenStandardOutput());
newOut.AutoFlush = true;
Console.SetOut(newOut);
Console.SetError(newOut);
}
*/
public static void Hide()
{
var ptr = GetStdHandle(-11);
if (!CloseHandle(ptr))
{
throw new Win32Exception();
}
ptr = IntPtr.Zero;
if (!FreeConsole())
{
throw new Win32Exception();
}
}
#endregion
}
}
Actually AllocConsole with SetStdHandle in a GUI application might be a safer approach. The problem with the "console hijacking" already mentioned, is that the console might not be a foreground window at all, (esp. considering the influx of new window managers in Vista/Windows 7) among other things.
As per Jeffrey Knight quote above, as soon as I run into situations where I need API calls to get something done, I tend to stop and ask myself "am I overcomplicating things?".
If what is wanted is to have some code and run it in Windows GUI mode or Console mode, consider moving the code used in both modes off to a code library DLL, and then having a Windows Forms application that uses that DLL, and a Console application that uses that DLL (i.e. if in Visual Studio you now have a three-project solution: library with the bulk of the code, GUI with just the Win Forms code, and Console with just your console code.)
And yet another belated answer.
I couldn't get any output to the console created with AllocConsole as per earlier suggestions, so instead I'm starting with Console application. Then, if the console is not needed:
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_HIDE = 0;
private const int SW_SHOW = 5;
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
public static bool HideConsole()
{
var hwnd = GetConsoleWindow();
GetWindowThreadProcessId(hwnd, out var pid);
if (pid != Process.GetCurrentProcess().Id) // It's not our console - don't mess with it.
return false;
ShowWindow(hwnd, SW_HIDE);
return true;
}
In wind32, console-mode applications are a completely different beast from the usual message-queue-receiving applications. They are declared and compile differently. You might create an application which has both a console part and normal window and hide one or the other. But suspect you will find the whole thing a bit more work than you thought.
Create a Windows Forms Application.
Set project properties in application to type console application.
The program will open a console window and show also the forms.
Call Console.Writeline() from the forms or the Program.cs to send messages to the console window.
You can comment in Program.cs
// Application.EnableVisualStyles();
// Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new Form1());
to avoid using Form1.
Tested with C# and VS2019.

Categories