///////////////////////////// // // // Sonic Robo Blast 2 // // Official Win32 Launcher // // // // By // // SSNTails // // ah518@tcnet.org // // (Sonic Team Junior) // // http://www.srb2.org // // // ///////////////////////////// // // This source code is released under // Public Domain. I hope it helps you // learn how to write exciting Win32 // applications in C! // // However, you may not alter this // program and continue to call it // the "Official Sonic Robo Blast 2 // Launcher". // // NOTE: Not all files in this project // are released under this license. // Any license mentioned in accompanying // source files overrides the license // mentioned here, sorry! // // SRB2Launcher.cpp : Defines the entry point for the application. // #include "stdafx.h" #include #include #include "SRB2Launcher.h" char TempString[256]; char Arguments[16384]; HWND mainHWND; HWND hostHWND; HWND joinHWND; HINSTANCE g_hInst; HANDLE ServerlistThread = 0; typedef struct { char nospecialrings; char suddendeath; char scoringtype[16]; char matchboxes[16]; int respawnitemtime; int timelimit; int pointlimit; } matchsettings_t; typedef struct { char raceitemboxes[16]; int numlaps; } racesettings_t; typedef struct { char nospecialrings; char matchboxes[16]; int respawnitemtime; int timelimit; int pointlimit; } tagsettings_t; typedef struct { char nospecialrings; char matchboxes[16]; int respawnitemtime; int timelimit; int flagtime; int pointlimit; } ctfsettings_t; typedef struct { char nofile; char nodownload; } joinsettings_t; typedef struct { matchsettings_t match; racesettings_t race; tagsettings_t tag; ctfsettings_t ctf; char gametype[16]; char startmap[9]; int maxplayers; char advancestage[16]; int inttime; char forceskin; char noautoaim; char nosend; char noadvertise; // Monitor Toggles... char teleporters[8]; char superring[8]; char silverring[8]; char supersneakers[8]; char invincibility[8]; char jumpshield[8]; char watershield[8]; char ringshield[8]; char fireshield[8]; char bombshield[8]; char oneup[8]; char eggmanbox[8]; } hostsettings_t; typedef struct { hostsettings_t host; joinsettings_t join; char EXEName[1024]; char ConfigFile[1024]; char ManualParameters[8192]; char PlayerName[24]; char PlayerColor[16]; char PlayerSkin[24]; } settings_t; // Whole structure is just dumped to a binary file when settings are saved. settings_t launchersettings; #define APPTITLE "Official Sonic Robo Blast 2 Launcher" #define APPVERSION "v0.1" #define APPAUTHOR "SSNTails" #define APPCOMPANY "Sonic Team Junior" LRESULT CALLBACK MainProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); // // RunSRB2 // // Runs SRB2 // returns true if successful // BOOL RunSRB2(void) { SHELLEXECUTEINFO lpExecInfo; BOOL result; char EXEName[1024]; memset(&lpExecInfo, 0, sizeof(SHELLEXECUTEINFO)); lpExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); SendMessage(GetDlgItem(mainHWND, IDC_EXENAME), WM_GETTEXT, sizeof(EXEName), (LPARAM)(LPCSTR)EXEName); lpExecInfo.lpFile = EXEName; lpExecInfo.lpParameters = Arguments; lpExecInfo.nShow = SW_SHOWNORMAL; lpExecInfo.hwnd = mainHWND; lpExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; lpExecInfo.lpVerb = "open"; result = ShellExecuteEx(&lpExecInfo); if(!result) { MessageBox(mainHWND, "Error starting the game!", "Error", MB_OK|MB_APPLMODAL|MB_ICONERROR); return false; } return true; } // // ChooseEXEName // // Provides a common dialog box // for selecting the desired executable. // void ChooseEXEName(void) { OPENFILENAME ofn; char FileBuffer[256]; ZeroMemory(&ofn, sizeof(ofn)); ofn.hwndOwner = NULL; FileBuffer[0] = '\0'; ofn.lpstrFilter = "Executable Files\0*.exe\0All Files\0*.*\0\0"; ofn.lpstrInitialDir = NULL; ofn.lpstrFile = FileBuffer; ofn.lStructSize = sizeof(ofn); ofn.nMaxFile = sizeof(FileBuffer); ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; if(GetOpenFileName(&ofn)) { SendMessage(GetDlgItem(mainHWND, IDC_EXENAME), WM_SETTEXT, 0, (LPARAM)(LPCSTR)FileBuffer); strcpy(launchersettings.EXEName, FileBuffer); } } // // ChooseConfigName // // Provides a common dialog box // for selecting the desired cfg file. // void ChooseConfigName(void) { OPENFILENAME ofn; char FileBuffer[256]; ZeroMemory(&ofn, sizeof(ofn)); ofn.hwndOwner = NULL; FileBuffer[0] = '\0'; ofn.lpstrFilter = "Config Files\0*.cfg\0All Files\0*.*\0\0"; ofn.lpstrInitialDir = NULL; ofn.lpstrFile = FileBuffer; ofn.lStructSize = sizeof(ofn); ofn.nMaxFile = sizeof(FileBuffer); ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; if(GetOpenFileName(&ofn)) { SendMessage(GetDlgItem(mainHWND, IDC_CONFIGFILE), WM_SETTEXT, 0, (LPARAM)(LPCSTR)FileBuffer); strcpy(launchersettings.ConfigFile, FileBuffer); } } // // Add External File // // Provides a common dialog box // for adding an external file. // void AddExternalFile(void) { OPENFILENAME ofn; char FileBuffer[256]; ZeroMemory(&ofn, sizeof(ofn)); ofn.hwndOwner = NULL; FileBuffer[0] = '\0'; ofn.lpstrFilter = "WAD/SOC Files\0*.soc;*.wad\0All Files\0*.*\0\0"; ofn.lpstrInitialDir = NULL; ofn.lpstrFile = FileBuffer; ofn.lStructSize = sizeof(ofn); ofn.nMaxFile = sizeof(FileBuffer); ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; if(GetOpenFileName(&ofn) && SendMessage(GetDlgItem(mainHWND, IDC_EXTFILECOMBO), CB_FINDSTRING, -1, (LPARAM)(LPCSTR)FileBuffer) == CB_ERR) SendMessage(GetDlgItem(mainHWND, IDC_EXTFILECOMBO), CB_ADDSTRING, 0, (LPARAM)(LPCSTR)FileBuffer); } // // CompileArguments // // Go through ALL of the settings // and put them into a parameter // string. Yikes! // void CompileArguments(void) { HWND temp; int numitems; int i; // Clear out the arguments, if any existed. memset(Arguments, 0, sizeof(Arguments)); // WAD/SOC Files Added temp = GetDlgItem(mainHWND, IDC_EXTFILECOMBO); if ((numitems = SendMessage(temp, CB_GETCOUNT, 0, 0)) > 0) { char tempbuffer[1024]; strcpy(Arguments, "-file "); for (i = 0; i < numitems; i++) { SendMessage(temp, CB_GETLBTEXT, i, (LPARAM)(LPCSTR)tempbuffer); strcat(Arguments, tempbuffer); strcat(Arguments, " "); } } // Manual Parameters temp = GetDlgItem(mainHWND, IDC_PARAMETERS); if (SendMessage(temp, WM_GETTEXTLENGTH, 0, 0) > 0) { char tempbuffer[8192]; SendMessage(temp, WM_GETTEXT, 8192, (LPARAM)(LPCSTR)tempbuffer); strcat(Arguments, tempbuffer); } } // // GetConfigVariable // // Pulls a value out of the chosen // config.cfg and places it into the // string supplied in 'dest' // BOOL GetConfigVariable(char* varname, char* dest) { FILE* f; int size = 0; char* buffer; char* posWeWant; char* stringstart; char varnamecpy[256]; varnamecpy[0] = '\n'; strncpy(varnamecpy+1, varname, 255); if(!(f = fopen(launchersettings.ConfigFile, "rb"))) return false; // Oops! // Get file size while(!feof(f)) { size++; fgetc(f); } fseek(f, 0, SEEK_SET); buffer = (char*)malloc(size); fread(buffer, size, 1, f); fclose(f); posWeWant = strstr(buffer, varname); if(posWeWant == NULL) { free(buffer); return false; } posWeWant++; // We are now at the line we want. // Get the variable from it while(*posWeWant != '\"') posWeWant++; posWeWant++; stringstart = posWeWant; while(*posWeWant != '\"') posWeWant++; *posWeWant = '\0'; strcpy(dest, stringstart); free(buffer); // Phew! return true; } SOCKET ConnectSocket(char* IPAddress, int portnumber) { DWORD dwDestAddr; SOCKADDR_IN sockAddrDest; SOCKET sockDest; // Create socket sockDest = socket(AF_INET, SOCK_STREAM, 0); if(sockDest == SOCKET_ERROR) { // printf("Could not create socket: %d\n", WSAGetLastError()); return INVALID_SOCKET; } // Convert address to in_addr (binary) format dwDestAddr = inet_addr(IPAddress); if(dwDestAddr == INADDR_NONE) { // It's not a xxx.xxx.xxx.xxx IP, so resolve through DNS struct hostent* pHE = gethostbyname(IPAddress); if(pHE == 0) { // printf("Unable to resolve address.\n"); return INVALID_SOCKET; } dwDestAddr = *((u_long*)pHE->h_addr_list[0]); } // Initialize SOCKADDR_IN with IP address, port number and address family memcpy(&sockAddrDest.sin_addr, &dwDestAddr, sizeof(DWORD)); sockAddrDest.sin_port = htons(portnumber); sockAddrDest.sin_family = AF_INET; // Attempt to connect to server if(connect(sockDest, (LPSOCKADDR)&sockAddrDest, sizeof(sockAddrDest)) == SOCKET_ERROR) { // printf("Could not connect to server socket: %d\n", WSAGetLastError()); closesocket(sockDest); return INVALID_SOCKET; } return sockDest; } // // MS_Write(): // static int MS_Write(msg_t *msg, SOCKET socket) { #ifdef NONET msg = NULL; return MS_WRITE_ERROR; #else int len; if (msg->length < 0) msg->length = (long)strlen(msg->buffer); len = msg->length + HEADER_SIZE; msg->type = htonl(msg->type); msg->length = htonl(msg->length); if (send(socket, (char *)msg, len, 0) != len) return MS_WRITE_ERROR; return 0; #endif } // // MS_Read(): // static int MS_Read(msg_t *msg, SOCKET socket) { #ifdef NONET msg = NULL; return MS_READ_ERROR; #else if (recv(socket, (char *)msg, HEADER_SIZE, 0) != HEADER_SIZE) return MS_READ_ERROR; msg->type = ntohl(msg->type); msg->length = ntohl(msg->length); if (!msg->length) // fix a bug in Windows 2000 return 0; if (recv(socket, (char *)msg->buffer, msg->length, 0) != msg->length) return MS_READ_ERROR; return 0; #endif } /** Gets a list of game servers from the master server. */ static inline int GetServersList(SOCKET socket) { msg_t msg; int count = 0; msg.type = GET_SERVER_MSG; msg.length = 0; if (MS_Write(&msg, socket) < 0) return MS_WRITE_ERROR; while (MS_Read(&msg, socket) >= 0) { if (!msg.length) { // if (!count) // printf("No server currently running.\n"); return MS_NO_ERROR; } count++; printf(msg.buffer); } return MS_READ_ERROR; } // // RunSocketStuff // // Thread that checks the masterserver for new games. void RunSocketStuff(HWND hListView) { WSADATA wsaData; SOCKET sock; int i = 0; char ServerAddressAndPort[256]; char Address[256]; char Port[8]; if(!GetConfigVariable("masterserver", ServerAddressAndPort)) // srb2.servegame.org:28900 { ServerlistThread = NULL; return; } strcpy(Address, ServerAddressAndPort); for(i = 0; i < (signed)strlen(Address); i++) { if(Address[i] == ':') { Address[i] = '\0'; break; } } for(i = 0; i < (signed)strlen(ServerAddressAndPort); i++) { if(ServerAddressAndPort[i] == ':') { strcpy(Port, &ServerAddressAndPort[i+1]); break; } } // Address now contains the hostname or IP // Port now contains the port number // Initialize WinSock if(WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { // printf("Could not initialize sockets.\n"); ServerlistThread = NULL; return; } // Create socket and connect to server sock = ConnectSocket(/*IPAddress*/0, /*PortNumber*/0); if(sock == INVALID_SOCKET) { // printf("Socket Error: %d\n", WSAGetLastError()); ServerlistThread = NULL; return; } // We're connected! // Now get information from server // Add games to listview box. ListView_DeleteAllItems(hListView); /* while (MoreServersStillExist) { GetTheNextServerInformation(); AddItemToList(hListView, servername, ping, players, gametype, level); } */ // close socket closesocket(sock); // Clean up WinSock if(WSACleanup() == SOCKET_ERROR) { // printf("Could not cleanup sockets: %d\n", WSAGetLastError()); ServerlistThread = NULL; return; } printf("Winsock thread terminated successfully.\n"); ServerlistThread = NULL; return; } BOOL GetGameList(HWND hListView) { DWORD dwThreadID; ServerlistThread = CreateThread( NULL, // default security 0, // default stack (LPTHREAD_START_ROUTINE)(void*)RunSocketStuff, // thread function hListView, // arguments 0, // default flags &dwThreadID); // don't need this, but it makes it happy (and compatible with old Win32 OSes) if(ServerlistThread == NULL) return false; return true; } void RegisterDialogClass(char* name, WNDPROC callback) { WNDCLASS wnd; wnd.style = CS_HREDRAW | CS_VREDRAW; wnd.cbWndExtra = DLGWINDOWEXTRA; wnd.cbClsExtra = 0; wnd.hCursor = LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)); wnd.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_ICON1)); wnd.hInstance = g_hInst; wnd.lpfnWndProc = callback; wnd.lpszClassName = name; wnd.lpszMenuName = NULL; wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW); if(!RegisterClass(&wnd)) { return; } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Prevent multiples instances of this app. CreateMutex(NULL, true, APPTITLE); if(GetLastError() == ERROR_ALREADY_EXISTS) return 0; g_hInst = hInstance; RegisterDialogClass("SRB2Launcher", MainProc); DialogBox(g_hInst, (LPCSTR)IDD_MAIN, NULL, (DLGPROC)MainProc); return 0; } // // InitHostOptionsComboBoxes // // Does what it says. // void InitHostOptionsComboBoxes(HWND hwnd) { HWND ctrl; ctrl = GetDlgItem(hwnd, IDC_MATCHBOXES); if(ctrl) { SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Normal (Default)"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Random"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Non-Random"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); } ctrl = GetDlgItem(hwnd, IDC_RACEITEMBOXES); if(ctrl) { SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Normal (Default)"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Random"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Teleports"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); } ctrl = GetDlgItem(hwnd, IDC_MATCH_SCORING); if(ctrl) { SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Normal (Default)"); SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Classic"); } } LRESULT CALLBACK MatchOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: InitHostOptionsComboBoxes(hwnd); break; case WM_DESTROY: EndDialog(hwnd, LOWORD(wParam)); break; case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; default: break; } break; } } return 0; } LRESULT CALLBACK RaceOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: InitHostOptionsComboBoxes(hwnd); break; case WM_DESTROY: EndDialog(hwnd, LOWORD(wParam)); break; case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; default: break; } break; } } return 0; } LRESULT CALLBACK TagOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: InitHostOptionsComboBoxes(hwnd); break; case WM_DESTROY: EndDialog(hwnd, LOWORD(wParam)); break; case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; default: break; } break; } } return 0; } LRESULT CALLBACK CTFOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: InitHostOptionsComboBoxes(hwnd); break; case WM_DESTROY: EndDialog(hwnd, LOWORD(wParam)); break; case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; default: break; } break; } } return 0; } LRESULT CALLBACK HostProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HWND temp; switch(message) { case WM_INITDIALOG: hostHWND = hwnd; temp = GetDlgItem(hwnd, IDC_ADVANCEMAP); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Off"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Next (Default)"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Random"); temp = GetDlgItem(hwnd, IDC_GAMETYPE); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Coop"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Match"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Team Match"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Race"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Time-Only Race"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Tag"); SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"CTF"); break; case WM_CREATE: { break; } case WM_DESTROY: { hostHWND = NULL; EndDialog(hwnd, LOWORD(wParam)); break; } case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; case IDC_OPTIONS: { int gametype; int dialognum; DLGPROC callbackfunc; // Grab the current gametype from the IDC_GAMETYPE // combo box and then display the appropriate // options dialog. temp = GetDlgItem(hostHWND, IDC_GAMETYPE); switch(SendMessage(temp, CB_GETCURSEL, 0, 0)) { case 0: gametype = 0; break; case 1: gametype = 1; break; case 2: gametype = 1; break; case 3: gametype = 2; break; case 4: gametype = 2; break; case 5: gametype = 3; break; case 6: gametype = 4; break; } switch(gametype) { case 1: dialognum = IDD_MATCHOPTIONS; callbackfunc = (DLGPROC)MatchOptionsDlgProc; break; case 2: dialognum = IDD_RACEOPTIONS; callbackfunc = (DLGPROC)RaceOptionsDlgProc; break; case 3: dialognum = IDD_TAGOPTIONS; callbackfunc = (DLGPROC)TagOptionsDlgProc; break; case 4: dialognum = IDD_CTFOPTIONS; callbackfunc = (DLGPROC)CTFOptionsDlgProc; break; case 0: default: // ??? dialognum = 0; callbackfunc = NULL; MessageBox(hostHWND, "This gametype does not have any additional options.", "Not Available", MB_OK|MB_APPLMODAL); break; } if(dialognum) DialogBox(g_hInst, (LPCSTR)dialognum, hostHWND, callbackfunc); } break; default: break; } break; } case WM_PAINT: { break; } } return 0; } // // AddItemToList // // Adds a game to the list view. // void AddItemToList(HWND hListView, char* servername, char* ping, char* players, char* gametype, char* level) { LVITEM lvTest; lvTest.mask = LVIF_TEXT | LVIF_STATE; lvTest.pszText = servername; lvTest.iIndent = 0; lvTest.stateMask = 0; lvTest.state = 0; lvTest.iSubItem = 0; lvTest.iItem = ListView_InsertItem(hListView, &lvTest); ListView_SetItemText(hListView,lvTest.iItem,1,ping); ListView_SetItemText(hListView,lvTest.iItem,2,players); ListView_SetItemText(hListView,lvTest.iItem,3,gametype); ListView_SetItemText(hListView,lvTest.iItem,4,level); } // // InitJoinGameColumns // // Initializes the column headers on the listview control // on the Join Game page. // void InitJoinGameColumns(HWND hDlg) { HWND hItemList; LVCOLUMN columns[10]; int i = 0; //Create the columns in the list control hItemList = GetDlgItem(hDlg, IDC_GAMELIST); columns[i].mask = LVCF_TEXT | LVCF_WIDTH; columns[i].pszText = "Server Name"; columns[i].cchTextMax = 256; columns[i].cx = 120; columns[i].fmt = LVCFMT_LEFT; ListView_InsertColumn(hItemList, i, &columns[i]); i++; columns[i].mask = LVCF_TEXT | LVCF_WIDTH; columns[i].pszText = "Ping"; columns[i].cchTextMax = 256; columns[i].cx = 80; columns[i].fmt = LVCFMT_LEFT; ListView_InsertColumn(hItemList, i, &columns[i]); i++; columns[i].mask = LVCF_TEXT | LVCF_WIDTH; columns[i].pszText = "Players"; columns[i].cchTextMax = 256; columns[i].cx = 80; columns[i].fmt = LVCFMT_LEFT; ListView_InsertColumn(hItemList, i, &columns[i]); i++; columns[i].mask = LVCF_TEXT | LVCF_WIDTH; columns[i].pszText = "Game Type"; columns[i].cchTextMax = 256; columns[i].cx = 80; columns[i].fmt = LVCFMT_LEFT; ListView_InsertColumn(hItemList, i, &columns[i]); i++; columns[i].mask = LVCF_TEXT | LVCF_WIDTH; columns[i].pszText = "Level"; columns[i].cchTextMax = 256; columns[i].cx = 120; columns[i].fmt = LVCFMT_LEFT; ListView_InsertColumn(hItemList, i, &columns[i]); } LRESULT CALLBACK JoinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: joinHWND = hwnd; InitJoinGameColumns(hwnd); // Start server listing thread // and grab game list. GetGameList(GetDlgItem(hwnd, IDC_GAMELIST)); break; case WM_DESTROY: joinHWND = NULL; // Terminate server listing thread. EndDialog(hwnd, LOWORD(wParam)); break; case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; case IDC_SEARCHGAMES: if(ServerlistThread == NULL) GetGameList(GetDlgItem(hwnd, IDC_GAMELIST)); break; default: break; } break; } case WM_PAINT: { break; } } return 0; } void InitializeDefaults(void) { memset(&launchersettings, 0, sizeof(launchersettings)); strcpy(launchersettings.EXEName, "srb2win.exe"); strcpy(launchersettings.ConfigFile, "config.cfg"); } LRESULT CALLBACK MainProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HWND temp; switch(message) { case WM_INITDIALOG: mainHWND = hwnd; InitializeDefaults(); SendMessage(GetDlgItem(hwnd, IDC_EXENAME), WM_SETTEXT, 0, (LPARAM)(LPCSTR)launchersettings.EXEName); SendMessage(GetDlgItem(hwnd, IDC_CONFIGFILE), WM_SETTEXT, 0, (LPARAM)(LPCSTR)launchersettings.ConfigFile); break; case WM_CREATE: { break; } case WM_DESTROY: { PostQuitMessage(0); break; } case WM_COMMAND: { switch(LOWORD(wParam)) { case 2: PostMessage(hwnd, WM_DESTROY, 0, 0); break; case IDC_ABOUT: // The About button. sprintf(TempString, "%s %s by %s - %s", APPTITLE, APPVERSION, APPAUTHOR, APPCOMPANY); MessageBox(mainHWND, TempString, "About", MB_OK|MB_APPLMODAL); break; case IDC_FINDEXENAME: ChooseEXEName(); break; case IDC_FINDCONFIGNAME: ChooseConfigName(); break; case IDC_ADDFILE: AddExternalFile(); break; case IDC_REMOVEFILE: temp = GetDlgItem(mainHWND, IDC_EXTFILECOMBO); SendMessage(temp, CB_DELETESTRING, SendMessage(temp, CB_GETCURSEL, 0, 0), 0); break; case IDC_HOSTGAME: DialogBox(g_hInst, (LPCSTR)IDD_HOSTGAME, mainHWND, (DLGPROC)HostProc); break; case IDC_JOINGAME: DialogBox(g_hInst, (LPCSTR)IDD_JOINGAME, mainHWND, (DLGPROC)JoinProc); break; case IDC_GO: CompileArguments(); RunSRB2(); break; default: break; } break; } case WM_PAINT: { break; } } return 0; }