Win32控制台问题

时间:2011-01-18 14:57:19

标签: winapi console native

是否可以创建一个程序,如果从控制台启动时作为控制台应用程序运行,并在启动时作为Windows程序(使用GUI)工作?

如果有可能 - 我该怎么做?

问候 托拜厄斯

6 个答案:

答案 0 :(得分:3)

如果您将程序设置为构建为GUI程序,则可以尝试使用AttachConsole()连接到控制台。您附加了OK然后从控制台启动,您可以继续将标准句柄重定向到新连接的控制台。

通过这种方式,您可以启动并查看是否从可以附加到的控制台启动,如果是,则成为控制台程序。如果你无法附加,你可以显示一个GUI。

我已经取得了一些成功,我的主要问题是当程序退出时重新显示命令窗口的提示(这是正常的控制台程序运行的方式),但我希望你能做一些聪明的事情(读取控制台缓冲区)在启动时,当你退出时找到重新显示的提示?)如果你真的想......

答案 1 :(得分:2)

如果您需要程序充当控制台应用程序(例如,将使用信息打印到控制台),则必须将其作为控制台应用程序进行压缩。 Windows应用程序无法访问控制台,cmd.exe将不会等待它完成,然后再打印提示并接受下一个命令。

最佳解决方案是拥有两个版本,一个用于命令行,一个用于GUI(用户通常通过桌面或开始菜单上的链接运行)。

如果您坚持使用单个二进制文件,则必须至少在短时间内出现控制台窗口。您可以使用

删除控制台窗口
FreeConsole();

如果它是连接到控制台的唯一进程,您可以告诉您应用程序是从GUI运行的。您可以使用GetConsoleProcessList查找附加到控制台的进程列表。

答案 2 :(得分:0)

程序本身永远不会知道它是如何启动的。除非您愿意将执行参数传递给程序。例如: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
   }
}

答案 3 :(得分:0)

您可以通过这样做来猜测是否从控制台启动:

CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
fConsole = csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y;

这是一个猜测 - 如果您的光标位置不是0,0而不是您在控制台中并且可以作为控制台应用程序工作。否则,去创建你的窗户。

另一种猜测方法是查看流程树并查看启动应用的流程。如果是cmd.exe,则进入控制台模式,否则进入GUI模式。

答案 4 :(得分: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

答案 5 :(得分:0)

这是Dan Tillett的答案,它非常有效。没有闪烁,没有.com和.exe来欺骗cmd.exe。似乎在.bat文件中完美地输入命令,具有焦点,没有焦点,并且双击GUI应用程序。

这是蜜蜂的膝盖!

这是描述它的网页,但我在这里发布了它,因为如果那个页面在下个月或者从现在开始的2年后变为404,那么我见过的优秀且“最完整”的解决方案将“脱离网格”

http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/

#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;
}