【问题标题】:Win32 console problemWin32控制台问题
【发布时间】:2011-06-11 03:57:47
【问题描述】:

如果从控制台启动,是否可以创建一个作为控制台应用程序工作的程序,否则可以创建一个在其他情况下作为 Windows 程序(带有 GUI)工作的程序?

如果可能的话,我该怎么做?

问候 托比亚斯

【问题讨论】:

    标签: winapi console native


    【解决方案1】:

    这是 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;
    }
    

    【讨论】:

      【解决方案2】:

      使其成为控制台应用程序并将其放入代码中:

      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

      【讨论】:

        【解决方案3】:

        如果您需要程序充当控制台应用程序(例如将使用信息打印到控制台),您必须编译为控制台应用程序。 Windows 应用程序将无法访问控制台,并且 cmd.exe 不会在打印提示和接受下一个命令之前等待它完成。

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

        如果您坚持使用单个二进制文件,您将不得不忍受控制台窗口的出现,至少在短时间内。您可以使用

        摆脱控制台窗口
        FreeConsole();
        

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

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

          • 但这不会创建一个新的控制台窗口而不是将您连接到启动您的控制台窗口的命令提示符吗?
          • 是的。从 GUI 程序调用 AttachConsole 没有记录在案的限制;这不是默认设置。
          【解决方案5】:

          您可以通过以下方式猜测您是否从控制台启动:

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

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

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            • 可以检查命令shell的父进程以确定它是通过cmd还是其他方式启动的。主要问题是如果在 pe 标头中设置了标志,则会显示 cmd 窗口。
            • 可以隐藏cmd窗口。这是可能的。
            • 您可以使用 GetStartUpInfo 检查标准句柄。 (msdn.microsoft.com/en-us/library/ms683230(v=vs.85).aspx) 加上 Len 的 Holgate 好主意。所以你错了,有办法。
            猜你喜欢
            • 1970-01-01
            • 2013-06-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-22
            相关资源
            最近更新 更多