我的问题非常简单。在Ubuntu中,程序通常可以使用或不使用GUI进行部署,也许使用像--showGUI这样的标志。我本质上想在Windows中重新创建此功能,但似乎Windows应用程序以win_main开头,而控制台应用程序以main开头。
那么产生这种行为所需的基本结构是什么?例如。在Visual Studio 2012中,我应该从Windows应用程序开始然后隐藏窗口并写入控制台吗?或者我可以从一个空的控制台应用程序开始,并使用Windows API创建一个窗口吗?
由于
(c / c ++,btw)
答案 0 :(得分:4)
控制台应用程序开始附加到控制台。然后它可以根据需要创建窗口 - 与专门为Windows子系统编写的应用程序基本没有区别。
理论上你可以做相反的事情:为windows子系统创建一个应用程序,然后将控制台连接到它。这增加了相当多的额外工作。标准库中的启动代码通常会将stdin / cin,stdout / cout,stderr / cerr附加到控制台。如果您创建一个Windows子系统程序,然后附加一个控制台,您基本上必须重现该代码以将控制台附加到标准流。
因此,通常最简单的方法是从为控制台子系统编写的程序开始,让它创建窗口,而不是从为子系统编写的程序开始,并创建/附加控制台。
就main
与WinMain
而言:它控制默认情况下程序将链接到哪个子系统。也就是说,如果你有一个名为main
的函数,它将默认为控制台子系统。如果你有一个名为WinMain
的函数,它将默认为windows子系统(我不记得如果你同时定义它们会做什么 - 我建议不要这样做。)
但是,如果需要,可以使用链接器标志强制子系统选择,因此可以使用main
作为windows子系统程序的入口点,或WinMain
作为条目指向控制台子系统程序。我通常建议不要做其中任何一个。
答案 1 :(得分:1)
Windows应用可以同时拥有GUI和控制台窗口。只是没有人以这种方式设置它们。你必须自己处理它。
以下是一些执行此操作的示例代码:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool ReconnectIO(bool OpenNewConsole);
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine,int nCmdShow)
{
MSG msg;
HWND hwnd;
WNDCLASS wc;
if(!ReconnectIO(false))
printf("Started from command prompt\n");
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpszClassName = "Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszMenuName = NULL;
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClass(&wc);
hwnd = CreateWindow(wc.lpszClassName, "Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 350, 250, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
printf("Entering GetMessage loop\n");
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
/*******************************************************************************
* NAME:
* ReconnectIO
*
* SYNOPSIS:
* bool ReconnectIO(bool OpenNewConsole);
*
* PARAMETERS:
* OpenNewConsole [I] -- This controls if we open a console window or not.
* True -- if the program was not started from an
* existing console open a new console window.
* False -- Only connect stdio if the program was
* started from an existing console.
*
* FUNCTION:
* This function connects up the stardard IO (stdout, stdin, stderr) to
* the windows console. It will open a new console window if needed
* (see 'OpenNewConsole').
*
* RETURNS:
* true -- A new console window was opened
* false -- Using an existing console window
*
* SEE ALSO:
*
******************************************************************************/
bool ReconnectIO(bool OpenNewConsole)
{
int hConHandle;
long lStdHandle;
FILE *fp;
bool MadeConsole;
MadeConsole=false;
if(!AttachConsole(ATTACH_PARENT_PROCESS))
{
if(!OpenNewConsole)
return false;
MadeConsole=true;
if(!AllocConsole())
return false; // Could throw here
}
// STDOUT to the console
lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );
// STDIN to the console
lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
// STDERR to the console
lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf( stderr, NULL, _IONBF, 0 );
// C++ streams to console
std::ios_base::sync_with_stdio();
return MadeConsole;
}
程序的顶部只是一个普通的Window程序,带有WinMain()入口点。神奇来自ReconnectIO()函数。如果需要,它将重新连接标准io并打开控制台窗口。
当您从命令行启动程序时,标准输出将转到它,当您从桌面启动时,只打开主窗口。
它确实有一个缺点,就是当从命令行启动时它立即返回而不是阻塞,直到程序退出。启动代码正在这样做,我还没有研究如何阻止它。
您可以从更多有关正在发生的事情的信息中查看http://dslweb.nwnexus.com/~ast/dload/guicon.htm。
答案 2 :(得分:0)
这在Windows中很难做到。
如果您创建使用Windows子系统的程序,则很难知道要连接到哪个控制台。 (如果它是从“运行”菜单或桌面快捷方式启动而没有控制台怎么办?)
如果您创建使用控制台子系统的程序,则始终获取控制台。 (您也可以创建窗口,但是,如果从现有控制台以外的其他位置启动,则无论您是否需要,新的控制台窗口都会闪烁。)
Visual Studio有一个黑客来解决这个问题。仔细观察,您会发现同一目录中有两个 devenv可执行文件:devenv.exe是一个Windows应用程序,devenv.com是一个控制台应用程序。
所有快捷方式都直接指向.exe。但是,如果您在控制台窗口中键入devenv
,并且安装目录位于您的路径中,它实际上将启动devenv.com,即控制台。我相信这是.com按字母顺序排在.exe之前的副作用。
如果你包含一个命令行选项(如/?
),devenv.com可以严格按照控制台模式处理它,它会。否则,它只会为您调用devenv.exe并退出。