【发布时间】:2011-06-11 03:57:47
【问题描述】:
如果从控制台启动,是否可以创建一个作为控制台应用程序工作的程序,否则可以创建一个在其他情况下作为 Windows 程序(带有 GUI)工作的程序?
如果可能的话,我该怎么做?
问候 托比亚斯
【问题讨论】:
如果从控制台启动,是否可以创建一个作为控制台应用程序工作的程序,否则可以创建一个在其他情况下作为 Windows 程序(带有 GUI)工作的程序?
如果可能的话,我该怎么做?
问候 托比亚斯
【问题讨论】:
这是 Dan Tillett 的回答,非常有效。没有闪烁,没有 .com 和 .exe 来欺骗 cmd.exe。似乎可以完美地在 .bat 文件中键入命令,有焦点、没有焦点以及作为双击 GUI 应用程序。
这是蜜蜂的膝盖!
这是描述它的网页,但我已将其发布在这里,因为如果该页面在下个月或 2 年后变为 404,那么我见过的出色且“最完整”的解决方案将是“脱离网格” .
#define WINVER 0x0501 // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#pragma comment(lib, "User32.lib")
// Attach output of application to parent console
static BOOL attachOutputToConsole(void) {
HANDLE consoleHandleOut, consoleHandleError;
int fdOut, fdError;
FILE *fpOut, *fpError;
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
//redirect unbuffered STDOUT to the console
consoleHandleOut = GetStdHandle(STD_OUTPUT_HANDLE);
fdOut = _open_osfhandle((intptr_t)consoleHandleOut, _O_TEXT);
fpOut = _fdopen(fdOut, "w" );
*stdout = *fpOut;
setvbuf(stdout, NULL, _IONBF, 0 );
//redirect unbuffered STDERR to the console
consoleHandleError = GetStdHandle(STD_ERROR_HANDLE);
fdError = _open_osfhandle((intptr_t)consoleHandleError, _O_TEXT);
fpError = _fdopen(fdError, "w" );
*stderr = *fpError;
setvbuf(stderr, NULL, _IONBF, 0 );
return TRUE;
}
//Not a console application
return FALSE;
}
//Send the "enter" to the console to release the command prompt on the parent console
static void sendEnterKey(void) {
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
//Send the "Enter" key
ip.ki.wVk = 0x0D; // virtual-key code for the "Enter" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "Enter" key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) {
int argc = __argc;
char **argv = __argv;
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nCmdShow);
BOOL console;
int i;
//Is the program running as console or GUI application
console = attachOutputToConsole();
if (console) {
//Print to stdout
printf("Program running as console application\n");
for (i = 0; i < argc; i++) {
printf("argv[%d] %s\n", i, argv[i]);
}
//Print to stderr
fprintf(stderr, "Output to stderr\n");
}
else {
MessageBox(NULL, "Program running as windows gui application",
"Windows GUI Application", MB_OK | MB_SETFOREGROUND);
}
//Send "enter" to release application from the console
//This is a hack, but if not used the console doesn't know the application has returned
//"enter" only sent if the console window is in focus
if (console && GetConsoleWindow() == GetForegroundWindow()){
sendEnterKey();
}
return 0;
}
【讨论】:
使其成为控制台应用程序并将其放入代码中:
void ConsoleWindowVisible(bool show)
{
DWORD dummy;
if
(
!show && // Trying to hide
GetConsoleProcessList(&dummy, 1) == 1 // Have our own console window
)
ShowWindow(GetConsoleWindow, SW_HIDE); // Hide the window
else // Trying to show or use parent console window
ShowWindow(GetConsoleWindow, SW_NORMAL); // Show the window
}
int main(int argc, char** argv)
{
ConsoleWindowVisible(false);
}
干杯。
gor.f.gyolchanyan@gmail.com
【讨论】:
如果您需要程序充当控制台应用程序(例如将使用信息打印到控制台),您必须编译为控制台应用程序。 Windows 应用程序将无法访问控制台,并且 cmd.exe 不会在打印提示和接受下一个命令之前等待它完成。
最好的解决方案是有两个版本,一个用于命令行,一个用于 GUI(用户通常通过桌面或开始菜单上的链接运行)。
如果您坚持使用单个二进制文件,您将不得不忍受控制台窗口的出现,至少在短时间内。您可以使用
摆脱控制台窗口FreeConsole();
如果您的应用程序是附加到控制台的唯一进程,您可以判断它是从 GUI 运行的。您可以使用GetConsoleProcessList 查找附加到控制台的进程列表。
【讨论】:
如果您将程序设置为构建为 GUI 程序,您可以尝试使用 AttachConsole() 附加到控制台。您附加 OK,然后您是从控制台启动的,您可以继续将标准句柄重定向到新附加的控制台。
通过这种方式,您可以启动并查看您是否从可以附加到的控制台启动,如果是,则成为控制台程序。如果无法附加,可以显示 GUI。
我已经取得了一些成功,我遇到的主要问题是当我的程序退出时重新显示命令窗口的提示符(这是正常控制台程序的操作方式),但我希望你可以做一些聪明的事情(阅读控制台缓冲区在启动并找到退出时重新显示的提示?)如果你真的想......
【讨论】:
AttachConsole 没有记录在案的限制;这不是默认设置。
您可以通过以下方式猜测您是否从控制台启动:
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
fConsole = csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y;
这是一个猜测 - 如果您的光标位置不是 0,0,那么您在控制台中并且可以作为控制台应用程序工作。否则去创建你的窗口。
另一种猜测方法是查看进程树,看看是哪个进程启动了您的应用。如果是cmd.exe进入控制台模式,否则进入GUI模式。
【讨论】:
程序本身永远不会知道它是如何启动的。除非您愿意将执行参数传递给程序。例如:program.exe -GUI ...您可以捕获传递的参数并根据传递的参数决定程序应该如何运行。
你的程序应该是这样的:
class MainClass
{
public static int Main(string[] args)
{
// Test if input arguments were supplied:
if(args[0]=="GUI")
new myGUI().show(); //runs an instance of your gui
else
//you know what should go here
}
}
【讨论】: