This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Commando/WINMAIN.CPP

808 lines
26 KiB
C++
Raw Permalink Normal View History

/*
** 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 <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** 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 <crtdbg.h>
#endif //_DEBUG
#if (_MSC_VER >= 1200)
#pragma warning(push,1)
#endif
#include <iostream>
#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_index<adapter_count; adapter_index++) {
D3DADAPTER_IDENTIFIER8 id;
::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8));
HRESULT res = d3d->GetAdapterIdentifier(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);
}