O que você quer fazer não é possível de uma maneira sã. Houve uma pergunta semelhante, então veja as respostas .
Depois, há também uma abordagem insana (site inativo - backup disponível aqui ), escrita por Jeffrey Knight :
Pergunta: Como faço para criar um aplicativo que pode ser executado no modo GUI (Windows) ou no modo de linha de comando / console?
À primeira vista, parece fácil: você cria um aplicativo de console, adiciona um formulário do Windows a ele e está pronto para começar. No entanto, há um problema:
Problema: se você executar no modo GUI, terá uma janela e um console incômodo à espreita em segundo plano e não terá como ocultá-lo.
O que as pessoas parecem querer é um verdadeiro aplicativo anfíbio que funcione sem problemas em qualquer modo.
Se você analisar, existem na verdade quatro casos de uso aqui:
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.
Estou postando o código para fazer isso, mas com uma ressalva.
Na verdade, acho que esse tipo de abordagem causará muito mais problemas no futuro do que vale a pena. Por exemplo, você terá que ter duas interfaces de usuário diferentes - uma para a GUI e outra para o comando / shell. Você vai ter que construir algum mecanismo lógico central estranho que abstrai da GUI vs. linha de comando, e só vai ficar estranho. Se fosse eu, eu voltaria atrás e pensaria em como isso será usado na prática e se esse tipo de troca de modo vale o trabalho. Portanto, a menos que algum caso especial exigisse isso, eu não usaria esse código, porque assim que me deparo com situações em que preciso de chamadas de API para fazer algo, tenho a tendência de parar e me perguntar "estou complicando as coisas? "
Tipo de saída = aplicativo do Windows
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
{
[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)
{
string mode = args.Length > 0 ? args[0] : "gui";
if (mode == "gui")
{
MessageBox.Show("Welcome to GUI mode");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else if (mode == "console")
{
IntPtr ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
Process process = Process.GetProcessById(u);
if (process.ProcessName == "cmd" )
{
AttachConsole(process.Id);
Console.WriteLine("hello. It looks like you started me from an existing console.");
}
else
{
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();
}
}
}
}
AttachConsole
com-1
(o valor da constante APIATTACH_PARENT_PROCESS
) em vez de esperar que a janela de primeiro plano seja a janela de comando certa para gravar.Isso é um pouco velho (OK, é MUITO velho), mas estou fazendo exatamente a mesma coisa agora. Aqui está uma solução muito simples que está funcionando para mim:
[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); }
fonte
Console.WriteLine
logs não estão aparecendo no caso iniciado em cmd com argsusing System.Runtime.InteropServices;
A maneira mais fácil é iniciar um aplicativo WinForms, ir para as configurações e alterar o tipo para um aplicativo de console.
fonte
aviso Legal
Existe uma maneira de fazer isso que é bastante simples, mas eu não sugeriria que seja uma boa abordagem para um aplicativo que você vai permitir que outras pessoas vejam. Mas se você tiver algum desenvolvedor que precise mostrar o console e os formulários do Windows ao mesmo tempo, isso pode ser feito facilmente.
Este método também suporta a exibição apenas da janela do Console, mas não oferece suporte à exibição apenas do Windows Form - ou seja, o Console sempre será mostrado. Você só pode interagir (ou seja, receber dados -
Console.ReadLine()
,Console.Read()
) com a janela do console se não mostrar os formulários da janela; saída para o console -Console.WriteLine()
- funciona em ambos os modos.Isso é fornecido como está; não há garantias de que isso não fará algo horrível mais tarde, mas funciona.
Etapas do projeto
Comece com um aplicativo de console padrão .
Marque o
Main
método como[STAThread]
Adicione uma referência em seu projeto para System.Windows.Forms
Adicione um Windows Form ao seu projeto.
Adicione o código de inicialização padrão do Windows ao seu
Main
método:Resultado final
Você terá um aplicativo que mostra o Console e, opcionalmente, os formulários do Windows.
Código de amostra
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"); } } }
fonte
Ressuscitando um tópico muito antigo mais uma vez, já que nenhuma das respostas aqui funcionou muito bem para mim.
Eu encontrei uma maneira simples que parece bastante robusta e simples. Funcionou para mim A ideia:
Exemplo:
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()); } } }
Uma palavra de cautela: parece que se você tentar gravar no console antes de anexar ou alocar um console, essa abordagem não funciona. Meu palpite é que a primeira vez que você chamar Console.Write / WriteLine, se ainda não houver um console, o Windows criará automaticamente um console oculto em algum lugar para você. (Portanto, talvez a resposta ShowConsoleWindow de Anthony seja melhor depois de você já ter escrito no console, e minha resposta é melhor se você ainda não escreveu no console). O importante a notar é que isso não funciona:
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()); } }
fonte
\bin\Debug>shareCheck.exe /once
e pressiono Enter, o prompt de comando é mostrado e o console começa a produzir:\bin\Debug>hello. It looks like you started me from an existing console.
e quando o programa termina não há prompt de comando, então a última linha de saída e a tela em branco que é um pouco malucaO que funcionou para mim foi escrever um aplicativo de console separadamente que fizesse o que eu queria, compilá-lo em um exe e depois fazer
Process.Start("MyConsoleapp.exe","Arguments")
fonte
Verifique este código-fonte. Todo o código comentado - usado para criar um console em um aplicativo do Windows. Não comentado - para ocultar o console em um aplicativo de console. A partir daqui . (Anteriormente
aqui.) Projetoreg2run
.// 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 } }
fonte
Na verdade, AllocConsole com SetStdHandle em um aplicativo GUI pode ser uma abordagem mais segura. O problema com o "sequestro de console" já mencionado, é que o console pode não ser uma janela em primeiro plano, (especialmente considerando o influxo de novos gerenciadores de janela no Vista / Windows 7) entre outras coisas.
fonte
No wind32, os aplicativos no modo console são completamente diferentes dos aplicativos usuais de recebimento de mensagens. Eles são declarados e compilados de maneira diferente. Você pode criar um aplicativo que tenha uma parte do console e uma janela normal e ocultar uma ou outra. Mas suspeite que você achará a coisa toda um pouco mais de trabalho do que você pensava.
fonte
De acordo com a citação de Jeffrey Knight acima, assim que me deparo com situações em que preciso de chamadas de API para fazer algo, tenho a tendência de parar e me perguntar "estou complicando demais as coisas?".
Se o que se deseja é ter algum código e executá-lo no modo Windows GUI ou no modo Console, considere mover o código usado em ambos os modos para uma biblioteca de código DLL e, em seguida, ter um aplicativo Windows Forms que usa essa DLL e um Console aplicativo que usa essa DLL (ou seja, se no Visual Studio você agora tem uma solução de três projetos: biblioteca com a maior parte do código, GUI apenas com o código do Win Forms e Console apenas com o código do console).
fonte
E ainda outra resposta tardia. Não consegui obter nenhuma saída para o console criado
AllocConsole
conforme as sugestões anteriores, então, em vez disso, estou começando com o aplicativo Console . Então, se o console não for necessário:[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; }
fonte