可以一个可执行的是既控制台和GUI应用程序?
-
20-08-2019 - |
题
我想做一个 C# 程序可以作为一个CLI或GUI应根据什么标志是通过它。可以这样做?
我已经找到这些相关的问题,但是他们不正是复盖我的情况:
解决方案
Jdigital的答案 点到 雷蒙德陈博客, 这解释了为什么你不能有一个应用程序的控制台节目和一个非控制台*
程序:在操作系统需要知道 程序开始之前运行 它子系统使用。一旦程序已经开始运行,是太迟回去,并请求的其他模式。
Cade的答案 点到 一个条约的运行。净它的应用程序与控制台.它使用技术的调用 AttachConsole
程序之后开始运行。这种做法所产生的效果是允许的程序写回到控制台窗口的命令提示开始的程序。但是意见中的那篇文章指出了我认为是一个致命的缺陷: 儿童的进程没有真正的控制。 控制台继续接受输入代表父母的过程中,以及父母进程是不知道,它应当等待的儿童完成运行之前使用的控制台上的其他东西。
陈第点 一篇文章俊峰张,解释了一些其他的技术.
第一是什么 下 使用。它通过实际上有两个项目。一个是 devenv.exe, ,这是主要的GUI程序,另一种是 devenv.com, 处理控制台模任务,但如果它是使用在非控制台的方式,它转发给它的任务 devenv.exe 然后退出。在技术依赖于Win32规则, com 文件得到的选择之前 exe 文件时,键入命令没有该文件的扩展。
有一个简单的变化在这Windows脚本主办。它提供了两个完全独立的二进制文件, wscript.exe 和 cscript.exe.同样,提供Java java.exe 控制台节目和 javaw.exe 对于不控制台节目。
俊峰的第二技术是什么 ildasm 使用。他报价的过程, ildasm's作者通过当使它运行这两种模式。最后,这里就是它:
- 该程序被标记为一个控制台的二元模式,所以它开始了一个控制台。这允许输入和输出的重新定向的工作,作为正常的。
- 如果程序没有控制台模式的命令行参数,它重新启动本身。
这是不够的,只是呼叫 FreeConsole
要做的第一个实例不再是控制台的节目。这是因为在进程开始的程序, cmd.exe, ,"知道"它开始了一台模式程序和正在等待程序停止运行。叫 FreeConsole
将使 ildasm 停止使用控制台,但是它不会使母体过程 开始 使用控制台。
所以第一个实例重新启动本身(一个额外的命令行参数,我想).当你打电话 CreateProcess
, 有两种不同标志的尝试, DETACHED_PROCESS
和 CREATE_NEW_CONSOLE
, 都会确保第二个实例将不会连接到母体控制台。在这之后,第一个实例可以终止,并允许该命令迅速恢复处理的命令。
副作用的这种技术是当你开始的程序从一个图形用户界面,将仍然是控制台。它将在屏幕上闪烁暂时然后消失。
该部在俊峰的文章中有关使用 editbin 改变程序的控制模式的标志是红鲱鱼,我想。编译器或发展的环境应提供的设定或选项,以控制这种二元。不应有任何需要修改任何东西之后。
底线,然后,是这 你可以有两个二进制文件,或者你可以有一个瞬间闪烁的一个窗口控制台.一旦你决定这是两害相权取其轻,你有你的选择的实现。
*
我说 非控制台 而不是的 GUI 因为否则这是一个错误的二分法。仅仅因为一个程序并没有控制台并不意味着它有一个图形用户界面。服务应用程序是一个主要的例子。此外,程序可以有控制台 和 窗户。
其他提示
检查雷蒙德的博客上的这个话题:
https://devblogs.microsoft.com/oldnewthing/20090101-00/?p=19643
他的第一句:"你不能,但是你可以尝试假。"
http://www.csharp411.com/console-output-from-winforms-application/
只是检查的命令行辩论之前对它 Application.
东西。
我要补充。净是可笑容易只是让控制台和GUI项目在同一解决方案,分享他们所有的集会,除了主要的。在这种情况下,可以使命线版本,只需启动GUI的版本,如果它启动与没有参数。你会得到一个闪烁的控制台。
有一个简单的方法做你想要什么。我总是用它的时候写的应用程序,应该有一个CLI和一个图形用户界面。你必须设置你的"OutputType"到"ConsoleApplication"这个工作。
class Program {
[DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow")]
private static extern IntPtr _GetConsoleWindow();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
/*
* This works as following:
* First we look for command line parameters and if there are any of them present, we run the CLI version.
* If there are no parameters, we try to find out if we are run inside a console and if so, we spawn a new copy of ourselves without a console.
* If there is no console at all, we show the GUI.
* We make an exception if we find out, that we're running inside visual studio to allow for easier debugging the GUI part.
* This way we're both a CLI and a GUI.
*/
if (args != null && args.Length > 0) {
// execute CLI - at least this is what I call, passing the given args.
// Change this call to match your program.
CLI.ParseCommandLineArguments(args);
} else {
var consoleHandle = _GetConsoleWindow();
// run GUI
if (consoleHandle == IntPtr.Zero || AppDomain.CurrentDomain.FriendlyName.Contains(".vshost"))
// we either have no console window or we're started from within visual studio
// This is the form I usually run. Change it to match your code.
Application.Run(new MainForm());
else {
// we found a console attached to us, so restart ourselves without one
Process.Start(new ProcessStartInfo(Assembly.GetEntryAssembly().Location) {
CreateNoWindow = true,
UseShellExecute = false
});
}
}
}
我认为,优选的技术是什么叫抢劫 下 技术的使用两个可执行文件:一个启动器"。com"和原始".exe"。这不是那个棘手的使用如果你有的样板代码的工作(见以下链接)。
该技术使用的技巧,以有"。com"是一个代理stdin/stdout/stderr,并启动相同的-的名字命名。exe文件。这给该行为的允许程序以预制件中的命令行模式时被称为形式的控制台(可能只有当某些命令的行参数检测到),同时仍然能够启动作为一个GUI申请免费的控制台。
我主持一个项目叫 dualsubsystem在谷歌的代码 更新老codeguru解决这种技术并提供来源代码和工作实例的二进制文件。
这里是我认为是简单的。净C#解决问题的办法。只要重申的问题,当运行控制台"版本"的应用程序从命令线路开关,控制台保持等待时间(不返回该命令迅速和进程保持运行),即使如果你有一个 Environment.Exit(0)
在结束你的代码。为了解决这个问题,只需话之前 Environment.Exit(0)
, 叫这样的:
SendKeys.SendWait("{ENTER}");
然后控制台获得最终进入关键,它需要返回该命令迅速和结束过程。注:不要叫 SendKeys.Send()
, 或程序将崩溃。
它仍然是必要的电话 AttachConsole()
正如在许多职位,但这个我没有得到任何命令窗口的闪烁的时候启动WinForm版本的应用程序。
这里是整个代码样本应用程序,我创造的(没有它的代码):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ConsoleWriter
{
static class Program
{
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
[STAThread]
static void Main(string[] args)
{
if(args.Length > 0 && args[0].ToUpperInvariant() == "/NOGUI")
{
AttachConsole(ATTACH_PARENT_PROCESS);
Console.WriteLine(Environment.NewLine + "This line prints on console.");
Console.WriteLine("Exiting...");
SendKeys.SendWait("{ENTER}");
Environment.Exit(0);
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
}
希望这可以帮助别人从也花天在这个问题。谢谢你的暗示去@dantill.
/*
** dual.c Runs as both CONSOLE and GUI app in Windows.
**
** This solution is based on the "Momentary Flicker" solution that Robert Kennedy
** discusses in the highest-rated answer (as of Jan 2013), i.e. the one drawback
** is that the console window will briefly flash up when run as a GUI. If you
** want to avoid this, you can create a shortcut to the executable and tell the
** short cut to run minimized. That will minimize the console window (which then
** immediately quits), but not the GUI window. If you want the GUI window to
** also run minimized, you have to also put -minimized on the command line.
**
** Tested under MinGW: gcc -o dual.exe dual.c -lgdi32
**
*/
#include <windows.h>
#include <stdio.h>
static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow);
static LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
static int win_started_from_console(void);
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp);
int main(int argc,char *argv[])
{
HINSTANCE hinst;
int i,gui,relaunch,minimized,started_from_console;
/*
** If not run from command-line, or if run with "-gui" option, then GUI mode
** Otherwise, CONSOLE app.
*/
started_from_console = win_started_from_console();
gui = !started_from_console;
relaunch=0;
minimized=0;
/*
** Check command options for forced GUI and/or re-launch
*/
for (i=1;i<argc;i++)
{
if (!strcmp(argv[i],"-minimized"))
minimized=1;
if (!strcmp(argv[i],"-gui"))
gui=1;
if (!strcmp(argv[i],"-gui-"))
gui=0;
if (!strcmp(argv[i],"-relaunch"))
relaunch=1;
}
if (!gui && !relaunch)
{
/* RUN AS CONSOLE APP */
printf("Console app only.\n");
printf("Usage: dual [-gui[-]] [-minimized].\n\n");
if (!started_from_console)
{
char buf[16];
printf("Press <Enter> to exit.\n");
fgets(buf,15,stdin);
}
return(0);
}
/* GUI mode */
/*
** If started from CONSOLE, but want to run in GUI mode, need to re-launch
** application to completely separate it from the console that started it.
**
** Technically, we don't have to re-launch if we are not started from
** a console to begin with, but by re-launching we can avoid the flicker of
** the console window when we start if we start from a shortcut which tells
** us to run minimized.
**
** If the user puts "-minimized" on the command-line, then there's
** no point to re-launching when double-clicked.
*/
if (!relaunch && (started_from_console || !minimized))
{
char exename[256];
char buf[512];
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
GetModuleFileNameA(NULL,exename,255);
sprintf(buf,"\"%s\" -relaunch",exename);
for (i=1;i<argc;i++)
{
if (strlen(argv[i])+3+strlen(buf) > 511)
break;
sprintf(&buf[strlen(buf)]," \"%s\"",argv[i]);
}
memset(&pi,0,sizeof(PROCESS_INFORMATION));
memset(&si,0,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwX = 0; /* Ignored unless si.dwFlags |= STARTF_USEPOSITION */
si.dwY = 0;
si.dwXSize = 0; /* Ignored unless si.dwFlags |= STARTF_USESIZE */
si.dwYSize = 0;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
/*
** Note that launching ourselves from a console will NOT create new console.
*/
CreateProcess(exename,buf,0,0,1,DETACHED_PROCESS,0,NULL,&si,&pi);
return(10); /* Re-launched return code */
}
/*
** GUI code starts here
*/
hinst=GetModuleHandle(NULL);
/* Free the console that we started with */
FreeConsole();
/* GUI call with functionality of WinMain */
return(my_win_main(hinst,argc,argv,minimized ? SW_MINIMIZE : SW_SHOWNORMAL));
}
static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
static char *wintitle="GUI Window";
wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = wintitle;
wndclass.hIconSm = NULL;
RegisterClassEx (&wndclass) ;
hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wintitle,0,
WS_VISIBLE|WS_OVERLAPPEDWINDOW,
100,100,400,200,NULL,NULL,hInstance,NULL);
SetWindowText(hwnd,wintitle);
ShowWindow(hwnd,iCmdShow);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);
}
static LRESULT CALLBACK WndProc (HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
if (iMsg==WM_DESTROY)
{
PostQuitMessage(0);
return(0);
}
return(DefWindowProc(hwnd,iMsg,wParam,lParam));
}
static int fwbp_pid;
static int fwbp_count;
static int win_started_from_console(void)
{
fwbp_pid=GetCurrentProcessId();
if (fwbp_pid==0)
return(0);
fwbp_count=0;
EnumWindows((WNDENUMPROC)find_win_by_procid,0L);
return(fwbp_count==0);
}
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp)
{
int pid;
GetWindowThreadProcessId(hwnd,(LPDWORD)&pid);
if (pid==fwbp_pid)
fwbp_count++;
return(TRUE);
}
我已经写了一个替代办法,可以避免的控制台上闪烁。看看 如何创建一个Windows程序,作为一个图形用户界面和应用控制台.
运行AllocConsole()在一个静态的构造对我的作品