/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando * * * * $Archive:: /Commando/Code/Commando/WINMAIN.CPP $* * * * $Author:: Steve_t $* * * * $Modtime:: 2/17/02 11:08a $* * * * $Revision:: 85 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * WinMain -- Win32 Program Entry Point! * * WIN_resize -- Surrender-required function which resizes the main window * * WIN_set_fullscreen -- Surrender-required function for toggling full-screen mode * * Main_Window_Proc -- Windows Proc for the main game window * * Create_Main_Window -- Creates the main game window * * On_Focus_Loss -- this function is called when the application loses focus * * On_Focus_Restore -- This function is called when the application gets focus * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "winmain.h" #define _WIN32_WINDOWS 0x0401 #include "win.h" #include "resource.h" #include "WW3D.H" #include "miscutil.h" #include "input.h" #include "useroptions.h" #include "WWAudio.H" #include "FFactory.H" #include "debug.h" #include "verchk.h" #include "devoptions.h" #include "dialogmgr.h" #include "renegadedialogmgr.h" #include "except.h" #include "DirectInput.h" #include "WebBrowser.h" #include "wwmemlog.h" #include "datasafe.h" #include "combatgmode.h" #include "registry.h" #include "init.h" #include "_globals.h" #include "buildnum.h" #include "dx8wrapper.h" #include "formconv.h" #include "autostart.h" #include "consolemode.h" #include "specialbuilds.h" #include "slavemaster.h" #include "serversettings.h" #ifdef _DEBUG #include #endif //_DEBUG #if (_MSC_VER >= 1200) #pragma warning(push,1) #endif #include #include "singletoninstancekeeper.h" #include "packetmgr.h" #if (_MSC_VER >= 1200) #pragma warning(pop) #endif //---------------------------------------------------------------------------- // Globals //---------------------------------------------------------------------------- extern "C" { HWND hWndMain; bool WIN_fullscreen = true; } //---------------------------------------------------------------------------- // Local functions //---------------------------------------------------------------------------- static BOOL Create_Main_Window(HANDLE hInstance, int nCmdShow); long FAR PASCAL Main_Window_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); void On_Focus_Loss(void); void On_Focus_Restore(void); void Split_Command_Line_Args(HINSTANCE instance, char *path_to_exe, char *command_line); void Set_Working_Directory(char *old_path, char *new_path); int Start_Application( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ); void Set_Working_Directory(HINSTANCE hInstance); #include "packet.h" #ifndef _MSC_VER long Top_Level_Exception_Filter(EXCEPTION_POINTERS *e_info) { return(Exception_Handler(e_info->ExceptionRecord->ExceptionCode, e_info)); } #endif //_MSC_VER /*********************************************************************************************** * WinMain -- Win32 Program Entry Point! * * * * INPUT: * * * * Standard WinMain inputs :-) * * * * OUTPUT: * * * * Standard WinMain output * * * * WARNINGS: * * * * HISTORY: * * 07/18/1997 GH : Created. * *=============================================================================================*/ int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WWMemoryLogClass::Init(); // This switches memlog from static to dynamic allocations mode #ifdef _DEBUG /* ** Setup to track memory heap integrity and check for ** memory leaks. Output is dumped to the debug string console. */ if (cDevOptions::CrtDbgEnabled.Is_True()) { _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); } /* ** Leak test */ //char *flibble = new char [1024]; //unsigned long *flibble2 = new unsigned long; //void *flibble3 = malloc(128); //flibble = flibble; //flibble2 = flibble2; //flibble3 = flibble3; #endif //_DEBUG #ifdef WWDEBUG // // If necessary, disable packet optimizations // if (cDevOptions::PacketOptimizationsEnabled.Is_False()) { PacketManager.Disable_Optimizations(); } #endif //WWDEBUG #ifdef _DEBUG // Denzil - DO NOT COMPILE INTO FINAL BUILD bool webInstalled = WebBrowser::InstallPrerequisites(); if (!webInstalled) { ::MessageBox(NULL, "Embedded browser prerequisites missing\n\nBrowser functionality questionable.\n\n(Please call Denzil @ 27272)", "Renegade Warning!", MB_ICONWARNING|MB_OK); } #endif // WWDEBUG if (!cUserOptions::Parse_Command_Line(lpCmdLine)) { return(0); } // // There's a couple of options we need for the FDS // #ifdef FREEDEDICATEDSERVER if (!SlaveMaster.Am_I_Slave() && !ServerSettingsClass::Is_Server_Settings_File_Set()) { cUserOptions::Set_Server_INI_File("STARTSERVER=server.ini"); } ConsoleBox.Set_Exclusive(true); #endif //FREEDEDICATEDSERVER // // Verify that we can execute (i.e. make sure there are no other instances running) // SingletonInstanceKeeperClass instance_keeper; if (instance_keeper.Verify_Safe_To_Execute () == false) { return 0; } // // Start the game! // int retval = Start_Application( hInstance, hPrevInstance, lpCmdLine, nCmdShow ); return retval; } static bool Graphics_Settings_Trouble_Shooting() { RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG ); if (!registry.Is_Valid()) return true; int progress=registry.Get_Int( VALUE_NAME_GAME_INITIALIZATION_IN_PROGRESS, 0 ); if (progress) { StringClass options="wwconfig.exe "; char* opts=options.Peek_Buffer(); STARTUPINFO startup_info; ZeroMemory(&startup_info,sizeof(STARTUPINFO)); startup_info.cb=sizeof(STARTUPINFO); PROCESS_INFORMATION process_info; CreateProcess( NULL, opts, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info); unsigned long exit_code=STILL_ACTIVE; unsigned res=0; do { res=GetExitCodeProcess(process_info.hProcess,&exit_code); if (!res) { return true; } Sleep(100); } while (exit_code==STILL_ACTIVE); return !exit_code; } return true; } typedef IDirect3D8* (WINAPI *Direct3DCreate8Type) (UINT SDKVersion); static Direct3DCreate8Type Direct3DCreate8Ptr = NULL; static HINSTANCE D3D8Lib = NULL; static bool Video_Card_Driver_Check() { RegistryClass render_registry(APPLICATION_SUB_KEY_NAME_RENDER); if (!render_registry.Is_Valid()) return true; int disabled=render_registry.Get_Int( "DriverVersionCheckDisabled" ); if (disabled>=87) return true; IDirect3D8* d3d=NULL; D3DCAPS8 tmp_caps; const D3DCAPS8* d3dcaps=NULL; D3DADAPTER_IDENTIFIER8 adapter_id; // Init D3D Init_D3D_To_WW3_Conversion(); D3D8Lib = LoadLibrary("D3D8.DLL"); if (D3D8Lib != NULL) { Direct3DCreate8Ptr = (Direct3DCreate8Type) GetProcAddress(D3D8Lib, "Direct3DCreate8"); if (Direct3DCreate8Ptr) { d3d=Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... if (!d3d) { FreeLibrary(D3D8Lib); return true; } } else { FreeLibrary(D3D8Lib); return(true); } } else { return(true); } // Select device. If there is already a device selected in the registry, use it. int current_adapter_index=D3DADAPTER_DEFAULT; // // Load the render device settings from the registry // char device_name[256] = { 0 }; render_registry.Get_String( VALUE_NAME_RENDER_DEVICE_NAME, device_name, sizeof(device_name)); int adapter_count = d3d->GetAdapterCount(); for (int adapter_index=0; adapter_indexGetAdapterIdentifier(adapter_index,D3DENUM_NO_WHQL_LEVEL,&id); // If device ok, check if it matches the currently set adapter name if (res == D3D_OK) { StringClass name(id.Description,true); if (name==device_name) { current_adapter_index=adapter_index; break; } } } if (FAILED(d3d->GetDeviceCaps( current_adapter_index, D3DDEVTYPE_HAL, &tmp_caps))) { d3d->Release(); FreeLibrary(D3D8Lib); return true; } ::ZeroMemory(&adapter_id, sizeof(D3DADAPTER_IDENTIFIER8)); if (FAILED( d3d->GetAdapterIdentifier( current_adapter_index, D3DENUM_NO_WHQL_LEVEL, &adapter_id))) { d3d->Release(); FreeLibrary(D3D8Lib); return true; } d3dcaps=&tmp_caps; DX8Caps caps(d3d,*d3dcaps,WW3D_FORMAT_UNKNOWN,adapter_id); DX8Caps::DriverVersionStatusType status=caps.Get_Driver_Version_Status(); d3d->Release(); FreeLibrary(D3D8Lib); switch (status) { default: case DX8Caps::DRIVER_STATUS_GOOD: case DX8Caps::DRIVER_STATUS_OK: case DX8Caps::DRIVER_STATUS_UNKNOWN: render_registry.Set_Int( "DriverVersionCheckDisabled",87 ); return true; break; case DX8Caps::DRIVER_STATUS_BAD: break; } StringClass options="wwconfig.exe -driverversion"; char* opts=options.Peek_Buffer(); STARTUPINFO startup_info; ZeroMemory(&startup_info,sizeof(STARTUPINFO)); startup_info.cb=sizeof(STARTUPINFO); PROCESS_INFORMATION process_info; if (!CreateProcess( NULL, opts, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info)) { return true; } unsigned long exit_code=STILL_ACTIVE; unsigned res=0; do { res=GetExitCodeProcess(process_info.hProcess,&exit_code); if (!res) { return true; } Sleep(100); } while (exit_code==STILL_ACTIVE); return !exit_code; } /*********************************************************************************************** * Start_Application -- Handles WinMain execution. * * * * INPUT: * * * * Standard WinMain inputs :-) * * * * OUTPUT: * * * * Standard WinMain output * * * * WARNINGS: * * * * HISTORY: * * 09/19/2001 PDS : Created. * *=============================================================================================*/ int Start_Application( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow ) { { WWMEMLOG(MEM_GAMEINIT); //LPSTR command = lpCmdLine; /* ** Set the working directory. */ Set_Working_Directory(hInstance); // // TEMP Dev code - check the working folder is correct! // char tmp_buffer[256]; char* tmp_ptr; if (!SearchPath( "data", "always.dat", NULL, sizeof(tmp_buffer), tmp_buffer, &tmp_ptr)) { MessageBox(NULL,"Set working folder and try again...","Invalid working folder",MB_OK); return 0; } /* ** Only do these checks if this isn't an auto-restart. If we are restarting then we must have run once OK already. Right? */ if (AutoRestart.Get_Restart_Flag() == false && !ConsoleBox.Is_Exclusive()) { if (!Video_Card_Driver_Check()) return 0; if (!Graphics_Settings_Trouble_Shooting()) return 0; } //Debug_Say(("Started logging at time %s", cMiscUtil::Get_Text_Time())); if (!Create_Main_Window(hInstance, nCmdShow)) return 0; Register_Thread_ID(GetCurrentThreadId(), "Main Thread", true); } int exitCode = EXIT_SUCCESS; #ifdef WWDEBUG if (cDevOptions::EnableExceptionHandler.Is_False()) { exitCode = Game_Main_Loop(); } else { #endif //WWDEBUG Register_Application_Exception_Callback(&Application_Exception_Callback); Register_Application_Version_Callback(&BuildInfoClass::Composite_Build_Info); #ifdef _MSC_VER /* ** The __try/__except construct is part of the WIN32 interface. This is not the same ** as C++ exception handling. There is no additional code overhead required ** with this interface and the compilers exception handling options should be disabled ** to prevent the compiler generating additional stack unwinding code. */ __try { #else SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) &Top_Level_Exception_Filter); #endif WWDEBUG_SAY(("Game_Main_Loop\n")); exitCode = Game_Main_Loop(); #ifdef _MSC_VER } __except(Exception_Handler(GetExceptionCode(), GetExceptionInformation())) {}; /* ** Set the exception filter to use on shutdown. */ #else SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) &Top_Level_Exception_Filter); #endif #ifdef WWDEBUG } #endif //WWDEBUG Unregister_Thread_ID(GetCurrentThreadId(), "Main Thread"); //Debug_Say(("Finished logging at time %s", cMiscUtil::Get_Text_Time())); return exitCode; } /*********************************************************************************************** * Main_Window_Proc -- Windows Proc for the main game window * * * * INPUT: * * * * Standard Windows Proc inputs * * * * OUTPUT: * * * * Standard Windows Proc output * * * * WARNINGS: * * * * HISTORY: * * 07/18/1997 GH : Created. * *=============================================================================================*/ long FAR PASCAL Main_Window_Proc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { static bool _reset = false; /* ** Pass this message through to the input handler. If the message ** was processed and requires no further action, then return with ** this information. */ if (_TheWWUIInput && Input::Is_Console_Enabled () == false) { LRESULT result = 0; //DialogWalker->Process_Message(hwnd, message, wParam, lParam, result); if (_TheWWUIInput->ProcessMessage(hwnd, message, wParam, lParam, result)) { return result; } } switch (message ) { /* ** basic management messages */ case WM_ACTIVATEAPP: if (wParam && !GameInFocus) { WWDEBUG_SAY(("***** FOCUS GAINED *****\n")); GameInFocus = true; On_Focus_Restore(); } else if (!wParam && GameInFocus) { WWDEBUG_SAY(("***** FOCUS LOST *****\n")); GameInFocus = false; On_Focus_Loss(); } return(0); case WM_ERASEBKGND: return 1; case WM_PAINT: ValidateRect(hwnd, NULL); break; /* ** minimize/maximize */ case WM_SYSKEYDOWN: if (wParam == VK_RETURN && ((lParam>>16) & KF_ALTDOWN) && !((lParam>>16) & KF_REPEAT)) { if (WIN_fullscreen) { WIN_fullscreen = false; } else { WIN_fullscreen = true; } } break; /* ** getch() */ case WM_CHAR: //Debug_Say(("WM_CHAR %d\n", wParam)); Input::Console_Add_Key( wParam ); break; /* ** Main window creation */ case WM_CREATE: break; /* ** Main window destruction */ case WM_DESTROY: ReleaseCapture (); PostQuitMessage (0); break; case WM_SYSCOMMAND: switch (wParam) { case SC_CLOSE: /* ** Windows sent us a close message. Probably in response to Alt-F4. Ignore it by ** pretending to handle the message and returning true; */ return (0); case SC_KEYMENU: /* ** Ignore all "menu-activation" commands. */ return (0); case SC_SCREENSAVE: /* ** Windoze is about to start the screen saver. If we just return without passing ** this message to DefWindowProc then the screen saver will not be allowed to start. */ return (0); } break; // Denzil - Using WM_xxxFOCUS messages to switch to windowed / fullscreen fails. #if(0) case WM_KILLFOCUS: { if (WW3D::Is_Initted ()) { // Get the current state of the redendering device int width = 0; int height = 0; int bits = 0; bool bwindowed = false; WW3D::Get_Device_Resolution (width, height, bits, bwindowed); // If we are running fullscreen, then toggle to 'windowed' // and minimze the window. if (bwindowed == false) { //Debug_Say(("WM_KILLFOCUS minimize")); WW3D::Set_Device_Resolution (-1, -1, -1, true); ::ShowWindow (hwnd, SW_MINIMIZE); _reset = true; } } } break; case WM_SETFOCUS: // If we need to reset the app to 'fullscreen' mode then // do so an restore the window. if (_reset == true) { WW3D::Set_Device_Resolution (-1, -1, -1, false); ::ShowWindow (hwnd, SW_RESTORE); _reset = false; } break; #endif case WM_COMMAND: if (LOWORD (wParam) == IDM_TOGGLE_FULLSCREEN) { // Ask WW3D to toggle the fullscreen mode for us. WW3D::Toggle_Windowed (); } break; default: break; } return DefWindowProc(hwnd, message, wParam, lParam); } /*********************************************************************************************** * Create_Main_Window -- Creates the main game window * * * * INPUT: * * * * hInstance -- Instance handle of the application * * nCmdShow -- how the window is to be shown * * * * OUTPUT: * * * * TRUE = success, FALSE = failure * * * * WARNINGS: * * * * HISTORY: * * 07/18/1997 GH : Created. * *=============================================================================================*/ static BOOL Create_Main_Window(HANDLE hInstance, int nCmdShow) { WNDCLASS wc; BOOL rc; ProgramInstance = (HINSTANCE)hInstance; if (!ConsoleBox.Is_Exclusive()) { wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = Main_Window_Proc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = (HINSTANCE)hInstance; wc.hIcon = LoadIcon( NULL, IDI_APPLICATION); wc.hCursor = LoadCursor( NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = SingletonInstanceKeeperClass::Get_GUID (); rc = RegisterClass( &wc); if (!rc ) return FALSE; // Assume windowed mode MainWindow = CreateWindowEx(0, SingletonInstanceKeeperClass::Get_GUID(), "Renegade", WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX|WS_CLIPCHILDREN, 0, 0, 0, 0, NULL, NULL, ProgramInstance, NULL); if (!MainWindow) { return FALSE; } SetFocus(MainWindow); } return TRUE; } /*********************************************************************************************** * On_Focus_Loss -- this function is called when the application loses focus * * * * INPUT: Nothing * * * * OUTPUT: Nothing * * * * WARNINGS: None * * * * HISTORY: * * 07/18/1997 GH : Created. * *=============================================================================================*/ void On_Focus_Loss(void) { DirectInput::Unacquire(); } /*********************************************************************************************** * On_Focus_Restore -- This function is called when the application gets focus * * * * INPUT: Nothing * * * * OUTPUT: Nothing * * * * WARNINGS: None * * * * HISTORY: * * 07/18/1997 GH : Created. * *=============================================================================================*/ void On_Focus_Restore(void) { if (WebBrowser::IsWebPageDisplayed() == false) { DirectInput::Acquire(); } GameModeManager::Hide_Render_Frames(1); // Hide the first rendered frame } void Prog_End(void) { } /*********************************************************************************************** * Set_Working_Directory -- Sets current directory to be the same as the .exe * * * * * * * * INPUT: Program instance * * * * OUTPUT: Nothing * * * * WARNINGS: None * * * * HISTORY: * * 11/6/2001 12:11PM ST : Created * *=============================================================================================*/ void Set_Working_Directory(HINSTANCE instance) { char path_to_exe[256]; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char path[_MAX_PATH]; GetModuleFileName(instance, path_to_exe, sizeof(path_to_exe)); _splitpath(path_to_exe, drive, dir, NULL, NULL); _makepath(path, drive, dir, NULL, NULL); SetCurrentDirectory(path); }