1074 lines
34 KiB
C++
1074 lines
34 KiB
C++
![]() |
/*
|
||
|
** Command & Conquer Generals(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/>.
|
||
|
*/
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// (c) 2001-2003 Electronic Arts Inc. //
|
||
|
// //
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// FILE: WinMain.cpp //////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Entry point for game application
|
||
|
//
|
||
|
// Author: Colin Day, April 2001
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||
|
#define WIN32_LEAN_AND_MEAN // only bare bones windows stuff wanted
|
||
|
#include <windows.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <crtdbg.h>
|
||
|
#include <eh.h>
|
||
|
#include <ole2.h>
|
||
|
#include <dbt.h>
|
||
|
|
||
|
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||
|
#include "WinMain.h"
|
||
|
#include "Lib/BaseType.h"
|
||
|
#include "Common/CopyProtection.h"
|
||
|
#include "Common/CriticalSection.h"
|
||
|
#include "Common/GlobalData.h"
|
||
|
#include "Common/GameEngine.h"
|
||
|
#include "Common/GameSounds.h"
|
||
|
#include "Common/Debug.h"
|
||
|
#include "Common/GameMemory.h"
|
||
|
#include "Common/SafeDisc/CdaPfn.h"
|
||
|
#include "Common/StackDump.h"
|
||
|
#include "Common/MessageStream.h"
|
||
|
#include "Common/Team.h"
|
||
|
#include "GameClient/InGameUI.h"
|
||
|
#include "GameClient/GameClient.h"
|
||
|
#include "GameLogic/GameLogic.h" ///< @todo for demo, remove
|
||
|
#include "GameClient/Mouse.h"
|
||
|
#include "GameClient/IMEManager.h"
|
||
|
#include "Win32Device/GameClient/Win32Mouse.h"
|
||
|
#include "Win32Device/Common/Win32GameEngine.h"
|
||
|
#include "Common/Version.h"
|
||
|
#include "BuildVersion.h"
|
||
|
#include "GeneratedVersion.h"
|
||
|
#include "Resource.h"
|
||
|
|
||
|
#ifdef _INTERNAL
|
||
|
// for occasional debugging...
|
||
|
//#pragma optimize("", off)
|
||
|
//#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
|
||
|
#endif
|
||
|
|
||
|
// GLOBALS ////////////////////////////////////////////////////////////////////
|
||
|
HINSTANCE ApplicationHInstance = NULL; ///< our application instance
|
||
|
HWND ApplicationHWnd = NULL; ///< our application window handle
|
||
|
Bool ApplicationIsWindowed = false;
|
||
|
Win32Mouse *TheWin32Mouse= NULL; ///< for the WndProc() only
|
||
|
DWORD TheMessageTime = 0; ///< For getting the time that a message was posted from Windows.
|
||
|
|
||
|
const Char *g_strFile = "data\\Generals.str";
|
||
|
const Char *g_csfFile = "data\\%s\\Generals.csf";
|
||
|
char *gAppPrefix = ""; /// So WB can have a different debug log file name.
|
||
|
|
||
|
static HANDLE GeneralsMutex = NULL;
|
||
|
#define GENERALS_GUID "685EAFF2-3216-4265-B047-251C5F4B82F3"
|
||
|
#define DEFAULT_XRESOLUTION 800
|
||
|
#define DEFAULT_YRESOLUTION 600
|
||
|
|
||
|
extern void Reset_D3D_Device(bool active);
|
||
|
|
||
|
static Bool gInitializing = false;
|
||
|
static Bool gDoPaint = true;
|
||
|
static Bool isWinMainActive = false;
|
||
|
|
||
|
static HBITMAP gLoadScreenBitmap = NULL;
|
||
|
|
||
|
//#define DEBUG_WINDOWS_MESSAGES
|
||
|
|
||
|
#ifdef DEBUG_WINDOWS_MESSAGES
|
||
|
static const char *messageToString(unsigned int message)
|
||
|
{
|
||
|
static char name[32];
|
||
|
|
||
|
switch (message)
|
||
|
{
|
||
|
case WM_NULL: return "WM_NULL";
|
||
|
case WM_CREATE: return "WM_CREATE";
|
||
|
case WM_DESTROY: return "WM_DESTROY";
|
||
|
case WM_MOVE: return "WM_MOVE";
|
||
|
case WM_SIZE: return "WM_SIZE";
|
||
|
case WM_ACTIVATE: return "WM_ACTIVATE";
|
||
|
case WM_SETFOCUS: return "WM_SETFOCUS";
|
||
|
case WM_KILLFOCUS: return "WM_KILLFOCUS";
|
||
|
case WM_ENABLE: return "WM_ENABLE";
|
||
|
case WM_SETREDRAW: return "WM_SETREDRAW";
|
||
|
case WM_SETTEXT: return "WM_SETTEXT";
|
||
|
case WM_GETTEXT: return "WM_GETTEXT";
|
||
|
case WM_GETTEXTLENGTH: return "WM_GETTEXTLENGTH";
|
||
|
case WM_PAINT: return "WM_PAINT";
|
||
|
case WM_CLOSE: return "WM_CLOSE";
|
||
|
case WM_QUERYENDSESSION: return "WM_QUERYENDSESSION";
|
||
|
case WM_QUIT: return "WM_QUIT";
|
||
|
case WM_QUERYOPEN: return "WM_QUERYOPEN";
|
||
|
case WM_ERASEBKGND: return "WM_ERASEBKGND";
|
||
|
case WM_SYSCOLORCHANGE: return "WM_SYSCOLORCHANGE";
|
||
|
case WM_ENDSESSION: return "WM_ENDSESSION";
|
||
|
case WM_SHOWWINDOW: return "WM_SHOWWINDOW";
|
||
|
case WM_WININICHANGE: return "WM_WININICHANGE";
|
||
|
case WM_DEVMODECHANGE: return "WM_DEVMODECHANGE";
|
||
|
case WM_ACTIVATEAPP: return "WM_ACTIVATEAPP";
|
||
|
case WM_FONTCHANGE: return "WM_FONTCHANGE";
|
||
|
case WM_TIMECHANGE: return "WM_TIMECHANGE";
|
||
|
case WM_CANCELMODE: return "WM_CANCELMODE";
|
||
|
case WM_SETCURSOR: return "WM_SETCURSOR";
|
||
|
case WM_MOUSEACTIVATE: return "WM_MOUSEACTIVATE";
|
||
|
case WM_CHILDACTIVATE: return "WM_CHILDACTIVATE";
|
||
|
case WM_QUEUESYNC: return "WM_QUEUESYNC";
|
||
|
case WM_GETMINMAXINFO: return "WM_GETMINMAXINFO";
|
||
|
case WM_PAINTICON: return "WM_PAINTICON";
|
||
|
case WM_ICONERASEBKGND: return "WM_ICONERASEBKGND";
|
||
|
case WM_NEXTDLGCTL: return "WM_NEXTDLGCTL";
|
||
|
case WM_SPOOLERSTATUS: return "WM_SPOOLERSTATUS";
|
||
|
case WM_DRAWITEM: return "WM_DRAWITEM";
|
||
|
case WM_MEASUREITEM: return "WM_MEASUREITEM";
|
||
|
case WM_DELETEITEM: return "WM_DELETEITEM";
|
||
|
case WM_VKEYTOITEM: return "WM_VKEYTOITEM";
|
||
|
case WM_CHARTOITEM: return "WM_CHARTOITEM";
|
||
|
case WM_SETFONT: return "WM_SETFONT";
|
||
|
case WM_GETFONT: return "WM_GETFONT";
|
||
|
case WM_SETHOTKEY: return "WM_SETHOTKEY";
|
||
|
case WM_GETHOTKEY: return "WM_GETHOTKEY";
|
||
|
case WM_QUERYDRAGICON: return "WM_QUERYDRAGICON";
|
||
|
case WM_COMPAREITEM: return "WM_COMPAREITEM";
|
||
|
case WM_COMPACTING: return "WM_COMPACTING";
|
||
|
case WM_COMMNOTIFY: return "WM_COMMNOTIFY";
|
||
|
case WM_WINDOWPOSCHANGING: return "WM_WINDOWPOSCHANGING";
|
||
|
case WM_WINDOWPOSCHANGED: return "WM_WINDOWPOSCHANGED";
|
||
|
case WM_POWER: return "WM_POWER";
|
||
|
case WM_COPYDATA: return "WM_COPYDATA";
|
||
|
case WM_CANCELJOURNAL: return "WM_CANCELJOURNAL";
|
||
|
case WM_NOTIFY: return "WM_NOTIFY";
|
||
|
case WM_INPUTLANGCHANGEREQUEST: return "WM_INPUTLANGCHANGEREQUES";
|
||
|
case WM_INPUTLANGCHANGE: return "WM_INPUTLANGCHANGE";
|
||
|
case WM_TCARD: return "WM_TCARD";
|
||
|
case WM_HELP: return "WM_HELP";
|
||
|
case WM_USERCHANGED: return "WM_USERCHANGED";
|
||
|
case WM_NOTIFYFORMAT: return "WM_NOTIFYFORMAT";
|
||
|
case WM_CONTEXTMENU: return "WM_CONTEXTMENU";
|
||
|
case WM_STYLECHANGING: return "WM_STYLECHANGING";
|
||
|
case WM_STYLECHANGED: return "WM_STYLECHANGED";
|
||
|
case WM_DISPLAYCHANGE: return "WM_DISPLAYCHANGE";
|
||
|
case WM_GETICON: return "WM_GETICON";
|
||
|
case WM_SETICON: return "WM_SETICON";
|
||
|
case WM_NCCREATE: return "WM_NCCREATE";
|
||
|
case WM_NCDESTROY: return "WM_NCDESTROY";
|
||
|
case WM_NCCALCSIZE: return "WM_NCCALCSIZE";
|
||
|
case WM_NCHITTEST: return "WM_NCHITTEST";
|
||
|
case WM_NCPAINT: return "WM_NCPAINT";
|
||
|
case WM_NCACTIVATE: return "WM_NCACTIVATE";
|
||
|
case WM_GETDLGCODE: return "WM_GETDLGCODE";
|
||
|
case WM_SYNCPAINT: return "WM_SYNCPAINT";
|
||
|
case WM_NCMOUSEMOVE: return "WM_NCMOUSEMOVE";
|
||
|
case WM_NCLBUTTONDOWN: return "WM_NCLBUTTONDOWN";
|
||
|
case WM_NCLBUTTONUP: return "WM_NCLBUTTONUP";
|
||
|
case WM_NCLBUTTONDBLCLK: return "WM_NCLBUTTONDBLCLK";
|
||
|
case WM_NCRBUTTONDOWN: return "WM_NCRBUTTONDOWN";
|
||
|
case WM_NCRBUTTONUP: return "WM_NCRBUTTONUP";
|
||
|
case WM_NCRBUTTONDBLCLK: return "WM_NCRBUTTONDBLCLK";
|
||
|
case WM_NCMBUTTONDOWN: return "WM_NCMBUTTONDOWN";
|
||
|
case WM_NCMBUTTONUP: return "WM_NCMBUTTONUP";
|
||
|
case WM_NCMBUTTONDBLCLK: return "WM_NCMBUTTONDBLCLK";
|
||
|
case WM_KEYDOWN: return "WM_KEYDOWN";
|
||
|
case WM_KEYUP: return "WM_KEYUP";
|
||
|
case WM_CHAR: return "WM_CHAR";
|
||
|
case WM_DEADCHAR: return "WM_DEADCHAR";
|
||
|
case WM_SYSKEYDOWN: return "WM_SYSKEYDOWN";
|
||
|
case WM_SYSKEYUP: return "WM_SYSKEYUP";
|
||
|
case WM_SYSCHAR: return "WM_SYSCHAR";
|
||
|
case WM_SYSDEADCHAR: return "WM_SYSDEADCHAR";
|
||
|
case WM_KEYLAST: return "WM_KEYLAST";
|
||
|
case WM_IME_STARTCOMPOSITION: return "WM_IME_STARTCOMPOSITION";
|
||
|
case WM_IME_ENDCOMPOSITION: return "WM_IME_ENDCOMPOSITION";
|
||
|
case WM_IME_COMPOSITION: return "WM_IME_COMPOSITION";
|
||
|
case WM_INITDIALOG: return "WM_INITDIALOG";
|
||
|
case WM_COMMAND: return "WM_COMMAND";
|
||
|
case WM_SYSCOMMAND: return "WM_SYSCOMMAND";
|
||
|
case WM_TIMER: return "WM_TIMER";
|
||
|
case WM_HSCROLL: return "WM_HSCROLL";
|
||
|
case WM_VSCROLL: return "WM_VSCROLL";
|
||
|
case WM_INITMENU: return "WM_INITMENU";
|
||
|
case WM_INITMENUPOPUP: return "WM_INITMENUPOPUP";
|
||
|
case WM_MENUSELECT: return "WM_MENUSELECT";
|
||
|
case WM_MENUCHAR: return "WM_MENUCHAR";
|
||
|
case WM_ENTERIDLE: return "WM_ENTERIDLE";
|
||
|
case WM_CTLCOLORMSGBOX: return "WM_CTLCOLORMSGBOX";
|
||
|
case WM_CTLCOLOREDIT: return "WM_CTLCOLOREDIT";
|
||
|
case WM_CTLCOLORLISTBOX: return "WM_CTLCOLORLISTBOX";
|
||
|
case WM_CTLCOLORBTN: return "WM_CTLCOLORBTN";
|
||
|
case WM_CTLCOLORDLG: return "WM_CTLCOLORDLG";
|
||
|
case WM_CTLCOLORSCROLLBAR: return "WM_CTLCOLORSCROLLBAR";
|
||
|
case WM_CTLCOLORSTATIC: return "WM_CTLCOLORSTATIC";
|
||
|
case WM_MOUSEMOVE: return "WM_MOUSEMOVE";
|
||
|
case WM_LBUTTONDOWN: return "WM_LBUTTONDOWN";
|
||
|
case WM_LBUTTONUP: return "WM_LBUTTONUP";
|
||
|
case WM_LBUTTONDBLCLK: return "WM_LBUTTONDBLCLK";
|
||
|
case WM_RBUTTONDOWN: return "WM_RBUTTONDOWN";
|
||
|
case WM_RBUTTONUP: return "WM_RBUTTONUP";
|
||
|
case WM_RBUTTONDBLCLK: return "WM_RBUTTONDBLCLK";
|
||
|
case WM_MBUTTONDOWN: return "WM_MBUTTONDOWN";
|
||
|
case WM_MBUTTONUP: return "WM_MBUTTONUP";
|
||
|
case WM_MBUTTONDBLCLK: return "WM_MBUTTONDBLCLK";
|
||
|
// case WM_MOUSEWHEEL: return "WM_MOUSEWHEEL";
|
||
|
case WM_PARENTNOTIFY: return "WM_PARENTNOTIFY";
|
||
|
case WM_ENTERMENULOOP: return "WM_ENTERMENULOOP";
|
||
|
case WM_EXITMENULOOP: return "WM_EXITMENULOOP";
|
||
|
case WM_NEXTMENU: return "WM_NEXTMENU";
|
||
|
case WM_SIZING: return "WM_SIZING";
|
||
|
case WM_CAPTURECHANGED: return "WM_CAPTURECHANGED";
|
||
|
case WM_MOVING: return "WM_MOVING";
|
||
|
case WM_POWERBROADCAST: return "WM_POWERBROADCAST";
|
||
|
case WM_DEVICECHANGE: return "WM_DEVICECHANGE";
|
||
|
case WM_MDICREATE: return "WM_MDICREATE";
|
||
|
case WM_MDIDESTROY: return "WM_MDIDESTROY";
|
||
|
case WM_MDIACTIVATE: return "WM_MDIACTIVATE";
|
||
|
case WM_MDIRESTORE: return "WM_MDIRESTORE";
|
||
|
case WM_MDINEXT: return "WM_MDINEXT";
|
||
|
case WM_MDIMAXIMIZE: return "WM_MDIMAXIMIZE";
|
||
|
case WM_MDITILE: return "WM_MDITILE";
|
||
|
case WM_MDICASCADE: return "WM_MDICASCADE";
|
||
|
case WM_MDIICONARRANGE: return "WM_MDIICONARRANGE";
|
||
|
case WM_MDIGETACTIVE: return "WM_MDIGETACTIVE";
|
||
|
case WM_MDISETMENU: return "WM_MDISETMENU";
|
||
|
case WM_ENTERSIZEMOVE: return "WM_ENTERSIZEMOVE";
|
||
|
case WM_EXITSIZEMOVE: return "WM_EXITSIZEMOVE";
|
||
|
case WM_DROPFILES: return "WM_DROPFILES";
|
||
|
case WM_MDIREFRESHMENU: return "WM_MDIREFRESHMENU";
|
||
|
case WM_IME_SETCONTEXT: return "WM_IME_SETCONTEXT";
|
||
|
case WM_IME_NOTIFY: return "WM_IME_NOTIFY";
|
||
|
case WM_IME_CONTROL: return "WM_IME_CONTROL";
|
||
|
case WM_IME_COMPOSITIONFULL: return "WM_IME_COMPOSITIONFULL";
|
||
|
case WM_IME_SELECT: return "WM_IME_SELECT";
|
||
|
case WM_IME_CHAR: return "WM_IME_CHAR";
|
||
|
case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN";
|
||
|
case WM_IME_KEYUP: return "WM_IME_KEYUP";
|
||
|
// case WM_MOUSEHOVER: return "WM_MOUSEHOVER";
|
||
|
// case WM_MOUSELEAVE: return "WM_MOUSELEAVE";
|
||
|
case WM_CUT: return "WM_CUT";
|
||
|
case WM_COPY: return "WM_COPY";
|
||
|
case WM_PASTE: return "WM_PASTE";
|
||
|
case WM_CLEAR: return "WM_CLEAR";
|
||
|
case WM_UNDO: return "WM_UNDO";
|
||
|
case WM_RENDERFORMAT: return "WM_RENDERFORMAT";
|
||
|
case WM_RENDERALLFORMATS: return "WM_RENDERALLFORMATS";
|
||
|
case WM_DESTROYCLIPBOARD: return "WM_DESTROYCLIPBOARD";
|
||
|
case WM_DRAWCLIPBOARD: return "WM_DRAWCLIPBOARD";
|
||
|
case WM_PAINTCLIPBOARD: return "WM_PAINTCLIPBOARD";
|
||
|
case WM_VSCROLLCLIPBOARD: return "WM_VSCROLLCLIPBOARD";
|
||
|
case WM_SIZECLIPBOARD: return "WM_SIZECLIPBOARD";
|
||
|
case WM_ASKCBFORMATNAME: return "WM_ASKCBFORMATNAME";
|
||
|
case WM_CHANGECBCHAIN: return "WM_CHANGECBCHAIN";
|
||
|
case WM_HSCROLLCLIPBOARD: return "WM_HSCROLLCLIPBOARD";
|
||
|
case WM_QUERYNEWPALETTE: return "WM_QUERYNEWPALETTE";
|
||
|
case WM_PALETTEISCHANGING: return "WM_PALETTEISCHANGING";
|
||
|
case WM_PALETTECHANGED: return "WM_PALETTECHANGED";
|
||
|
case WM_HOTKEY: return "WM_HOTKEY";
|
||
|
case WM_PRINT: return "WM_PRINT";
|
||
|
case WM_PRINTCLIENT: return "WM_PRINTCLIENT";
|
||
|
case WM_HANDHELDFIRST: return "WM_HANDHELDFIRST";
|
||
|
case WM_HANDHELDLAST: return "WM_HANDHELDLAST";
|
||
|
case WM_AFXFIRST: return "WM_AFXFIRST";
|
||
|
case WM_AFXLAST: return "WM_AFXLAST";
|
||
|
case WM_PENWINFIRST: return "WM_PENWINFIRST";
|
||
|
case WM_PENWINLAST: return "WM_PENWINLAST";
|
||
|
default: return "WM_UNKNOWN";
|
||
|
};
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// WndProc ====================================================================
|
||
|
/** Window Procedure */
|
||
|
//=============================================================================
|
||
|
LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
|
||
|
WPARAM wParam, LPARAM lParam )
|
||
|
{
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// First let the IME manager do it's stuff.
|
||
|
if ( TheIMEManager )
|
||
|
{
|
||
|
if ( TheIMEManager->serviceIMEMessage( hWnd, message, wParam, lParam ) )
|
||
|
{
|
||
|
// The manager intercepted an IME message so return the result
|
||
|
return TheIMEManager->result();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DO_COPY_PROTECTION
|
||
|
// Check for messages from the launcher
|
||
|
CopyProtect::checkForMessage(message, lParam);
|
||
|
#endif
|
||
|
|
||
|
#ifdef DEBUG_WINDOWS_MESSAGES
|
||
|
static msgCount=0;
|
||
|
char testString[256];
|
||
|
sprintf(testString,"\n%d: %s (%X,%X)", msgCount++,messageToString(message), wParam, lParam);
|
||
|
OutputDebugString(testString);
|
||
|
#endif
|
||
|
|
||
|
// handle all window messages
|
||
|
switch( message )
|
||
|
{
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_NCHITTEST:
|
||
|
// Prevent the user from selecting the menu in fullscreen mode
|
||
|
if( !ApplicationIsWindowed )
|
||
|
return HTCLIENT;
|
||
|
break;
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_POWERBROADCAST:
|
||
|
switch( wParam )
|
||
|
{
|
||
|
#ifndef PBT_APMQUERYSUSPEND
|
||
|
#define PBT_APMQUERYSUSPEND 0x0000
|
||
|
#endif
|
||
|
case PBT_APMQUERYSUSPEND:
|
||
|
// At this point, the app should save any data for open
|
||
|
// network connections, files, etc., and prepare to go into
|
||
|
// a suspended mode.
|
||
|
return TRUE;
|
||
|
|
||
|
#ifndef PBT_APMRESUMESUSPEND
|
||
|
#define PBT_APMRESUMESUSPEND 0x0007
|
||
|
#endif
|
||
|
case PBT_APMRESUMESUSPEND:
|
||
|
// At this point, the app should recover any data, network
|
||
|
// connections, files, etc., and resume running from when
|
||
|
// the app was suspended.
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_SYSCOMMAND:
|
||
|
// Prevent moving/sizing and power loss in fullscreen mode
|
||
|
switch( wParam )
|
||
|
{
|
||
|
case SC_MOVE:
|
||
|
case SC_SIZE:
|
||
|
case SC_MAXIMIZE:
|
||
|
case SC_KEYMENU:
|
||
|
case SC_MONITORPOWER:
|
||
|
if( FALSE == ApplicationIsWindowed )
|
||
|
return 1;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_CLOSE:
|
||
|
TheGameEngine->checkAbnormalQuitting();
|
||
|
TheGameEngine->reset();
|
||
|
TheGameEngine->setQuitting(TRUE);
|
||
|
_exit(EXIT_SUCCESS);
|
||
|
return 0;
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
case WM_SETFOCUS:
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// reset the state of our keyboard cause we haven't been paying
|
||
|
// attention to the keys while focus was away
|
||
|
//
|
||
|
if( TheKeyboard )
|
||
|
TheKeyboard->resetKeys();
|
||
|
|
||
|
if (TheWin32Mouse)
|
||
|
TheWin32Mouse->lostFocus(FALSE);
|
||
|
|
||
|
break;
|
||
|
|
||
|
} // end set focus
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_SIZE:
|
||
|
// When W3D initializes, it resizes the window. So stop repainting.
|
||
|
if (!gInitializing)
|
||
|
gDoPaint = false;
|
||
|
break;
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_KILLFOCUS:
|
||
|
{
|
||
|
if (TheKeyboard )
|
||
|
TheKeyboard->resetKeys();
|
||
|
if (TheWin32Mouse)
|
||
|
TheWin32Mouse->lostFocus(TRUE);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_ACTIVATEAPP:
|
||
|
{
|
||
|
// DWORD threadId=GetCurrentThreadId();
|
||
|
if ((bool) wParam != isWinMainActive)
|
||
|
{ isWinMainActive = (BOOL) wParam;
|
||
|
|
||
|
if (TheGameEngine)
|
||
|
TheGameEngine->setIsActive(isWinMainActive);
|
||
|
|
||
|
Reset_D3D_Device(isWinMainActive);
|
||
|
if (isWinMainActive)
|
||
|
{ //restore mouse cursor to our custom version.
|
||
|
if (TheWin32Mouse)
|
||
|
TheWin32Mouse->setCursor(TheWin32Mouse->getMouseCursor());
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_ACTIVATE:
|
||
|
{
|
||
|
Int active = LOWORD( wParam );
|
||
|
|
||
|
//
|
||
|
// when window is becoming deactivated we must release mouse cursor
|
||
|
// locks on our region, otherwise set the mouse limit region again
|
||
|
// which will clip the cursor to our window
|
||
|
//
|
||
|
if( active == WA_INACTIVE )
|
||
|
{
|
||
|
|
||
|
ClipCursor( NULL );
|
||
|
if (TheAudio)
|
||
|
TheAudio->loseFocus();
|
||
|
} // end if
|
||
|
else
|
||
|
{
|
||
|
if( TheMouse )
|
||
|
TheMouse->setMouseLimits();
|
||
|
|
||
|
if (TheAudio)
|
||
|
TheAudio->regainFocus();
|
||
|
|
||
|
} // end else
|
||
|
break;
|
||
|
|
||
|
} // end case activate
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_KEYDOWN:
|
||
|
{
|
||
|
Int key = (Int)wParam;
|
||
|
|
||
|
switch( key )
|
||
|
{
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
case VK_ESCAPE:
|
||
|
{
|
||
|
|
||
|
PostQuitMessage( 0 );
|
||
|
break;
|
||
|
|
||
|
} // end VK_ESCAPE
|
||
|
|
||
|
|
||
|
} // end switch
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end WM_KEYDOWN
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_LBUTTONDOWN:
|
||
|
case WM_LBUTTONUP:
|
||
|
case WM_LBUTTONDBLCLK:
|
||
|
|
||
|
case WM_MBUTTONDOWN:
|
||
|
case WM_MBUTTONUP:
|
||
|
case WM_MBUTTONDBLCLK:
|
||
|
|
||
|
case WM_RBUTTONDOWN:
|
||
|
case WM_RBUTTONUP:
|
||
|
case WM_RBUTTONDBLCLK:
|
||
|
{
|
||
|
|
||
|
if( TheWin32Mouse )
|
||
|
TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end WM_LBUTTONDOWN
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case 0x020A: // WM_MOUSEWHEEL
|
||
|
{
|
||
|
long x = (long) LOWORD(lParam);
|
||
|
long y = (long) HIWORD(lParam);
|
||
|
RECT rect;
|
||
|
|
||
|
// ignore when outside of client area
|
||
|
GetWindowRect( ApplicationHWnd, &rect );
|
||
|
if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom )
|
||
|
return 0;
|
||
|
|
||
|
if( TheWin32Mouse )
|
||
|
TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end WM_MOUSEWHEEL
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_MOUSEMOVE:
|
||
|
{
|
||
|
Int x = (Int)LOWORD( lParam );
|
||
|
Int y = (Int)HIWORD( lParam );
|
||
|
RECT rect;
|
||
|
// Int keys = wParam;
|
||
|
|
||
|
// ignore when outside of client area
|
||
|
GetClientRect( ApplicationHWnd, &rect );
|
||
|
if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom )
|
||
|
return 0;
|
||
|
|
||
|
if( TheWin32Mouse )
|
||
|
TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end WM_MOUSEMOVE
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
case WM_SETCURSOR:
|
||
|
{
|
||
|
if (TheWin32Mouse && (HWND)wParam == ApplicationHWnd)
|
||
|
TheWin32Mouse->setCursor(TheWin32Mouse->getMouseCursor());
|
||
|
return TRUE; //tell Windows not to reset mouse cursor image to default.
|
||
|
}
|
||
|
|
||
|
case WM_PAINT:
|
||
|
{
|
||
|
if (gDoPaint) {
|
||
|
PAINTSTRUCT paint;
|
||
|
HDC dc = ::BeginPaint(hWnd, &paint);
|
||
|
#if 0
|
||
|
::SetTextColor(dc, RGB(255,255,255));
|
||
|
::SetBkColor(dc, RGB(0,0,0));
|
||
|
::TextOut(dc, 30, 30, "Loading Command & Conquer Generals...", 37);
|
||
|
#endif
|
||
|
if (gLoadScreenBitmap!=NULL) {
|
||
|
Int savContext = ::SaveDC(dc);
|
||
|
HDC tmpDC = ::CreateCompatibleDC(dc);
|
||
|
HBITMAP savBitmap = (HBITMAP)::SelectObject(tmpDC, gLoadScreenBitmap);
|
||
|
::BitBlt(dc, 0, 0, DEFAULT_XRESOLUTION, DEFAULT_YRESOLUTION, tmpDC, 0, 0, SRCCOPY);
|
||
|
::SelectObject(tmpDC, savBitmap);
|
||
|
::DeleteDC(tmpDC);
|
||
|
::RestoreDC(dc, savContext);
|
||
|
}
|
||
|
::EndPaint(hWnd, &paint);
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WM_ERASEBKGND:
|
||
|
{
|
||
|
if (!gDoPaint)
|
||
|
return TRUE; //we don't need to erase the background because we always draw entire window.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Well, it was a nice idea, but we don't get a message for an ejection.
|
||
|
// (Really unforunate, actually.) I'm leaving this in in-case some one wants
|
||
|
// to trap a different device change (for instance, removal of a mouse) - jkmcd
|
||
|
#if 0
|
||
|
case WM_DEVICECHANGE:
|
||
|
{
|
||
|
if (((UINT) wParam) == DBT_DEVICEREMOVEPENDING)
|
||
|
{
|
||
|
DEV_BROADCAST_HDR *hdr = (DEV_BROADCAST_HDR*) lParam;
|
||
|
if (!hdr) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (hdr->dbch_devicetype != DBT_DEVTYP_VOLUME) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Lets discuss how Windows is a flaming pile of poo. I'm now casting the header
|
||
|
// directly into the structure, because its the one I want, and this is just how
|
||
|
// its done. I hate Windows. - jkmcd
|
||
|
DEV_BROADCAST_VOLUME *vol = (DEV_BROADCAST_VOLUME*) (hdr);
|
||
|
|
||
|
// @todo - Yikes. This could cause us all kinds of pain. I don't really want
|
||
|
// to even think about the stink this could cause us.
|
||
|
TheFileSystem->unloadMusicFilesFromCD(vol->dbcv_unitmask);
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
} // end switch
|
||
|
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
RELEASE_CRASH(("Uncaught exception in Main::WndProc... probably should not happen\n"));
|
||
|
// no rethrow
|
||
|
}
|
||
|
|
||
|
//In full-screen mode, only pass these messages onto the default windows handler.
|
||
|
//Appears to fix issues with dual monitor systems but doesn't seem safe?
|
||
|
///@todo: Look into proper support for dual monitor systems.
|
||
|
/* if (!ApplicationIsWindowed)
|
||
|
switch (message)
|
||
|
{
|
||
|
case WM_PAINT:
|
||
|
case WM_NCCREATE:
|
||
|
case WM_NCDESTROY:
|
||
|
case WM_NCCALCSIZE:
|
||
|
case WM_NCPAINT:
|
||
|
return DefWindowProc( hWnd, message, wParam, lParam );
|
||
|
}
|
||
|
return 0;*/
|
||
|
|
||
|
return DefWindowProc( hWnd, message, wParam, lParam );
|
||
|
|
||
|
} // end WndProc
|
||
|
|
||
|
// initializeAppWindows =======================================================
|
||
|
/** Register windows class and create application windows. */
|
||
|
//=============================================================================
|
||
|
static Bool initializeAppWindows( HINSTANCE hInstance, Int nCmdShow, Bool runWindowed )
|
||
|
{
|
||
|
DWORD windowStyle;
|
||
|
Int startWidth = DEFAULT_XRESOLUTION,
|
||
|
startHeight = DEFAULT_YRESOLUTION;
|
||
|
|
||
|
// register the window class
|
||
|
|
||
|
WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, WndProc, 0, 0, hInstance,
|
||
|
LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ApplicationIcon)),
|
||
|
NULL/*LoadCursor(NULL, IDC_ARROW)*/,
|
||
|
(HBRUSH)GetStockObject(BLACK_BRUSH), NULL,
|
||
|
TEXT("Game Window") };
|
||
|
RegisterClass( &wndClass );
|
||
|
|
||
|
// Create our main window
|
||
|
windowStyle = WS_POPUP|WS_VISIBLE;
|
||
|
if (runWindowed)
|
||
|
windowStyle |= WS_DLGFRAME | WS_CAPTION | WS_SYSMENU;
|
||
|
else
|
||
|
windowStyle |= WS_EX_TOPMOST | WS_SYSMENU;
|
||
|
|
||
|
RECT rect;
|
||
|
rect.left = 0;
|
||
|
rect.top = 0;
|
||
|
rect.right = startWidth;
|
||
|
rect.bottom = startHeight;
|
||
|
AdjustWindowRect (&rect, windowStyle, FALSE);
|
||
|
if (runWindowed) {
|
||
|
// Makes the normal debug 800x600 window center in the screen.
|
||
|
startWidth = DEFAULT_XRESOLUTION;
|
||
|
startHeight= DEFAULT_YRESOLUTION;
|
||
|
}
|
||
|
|
||
|
gInitializing = true;
|
||
|
|
||
|
HWND hWnd = CreateWindow( TEXT("Game Window"),
|
||
|
TEXT("Command and Conquer Generals"),
|
||
|
windowStyle,
|
||
|
(GetSystemMetrics( SM_CXSCREEN ) / 2) - (startWidth / 2), // original position X
|
||
|
(GetSystemMetrics( SM_CYSCREEN ) / 2) - (startHeight / 2),// original position Y
|
||
|
// Lorenzen nudged the window higher
|
||
|
// so the constantdebug report would
|
||
|
// not get obliterated by assert windows, thank you.
|
||
|
//(GetSystemMetrics( SM_CXSCREEN ) / 2) - (startWidth / 2), //this works with any screen res
|
||
|
//(GetSystemMetrics( SM_CYSCREEN ) / 25) - (startHeight / 25),//this works with any screen res
|
||
|
rect.right-rect.left,
|
||
|
rect.bottom-rect.top,
|
||
|
0L,
|
||
|
0L,
|
||
|
hInstance,
|
||
|
0L );
|
||
|
|
||
|
|
||
|
if (!runWindowed)
|
||
|
{ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,SWP_NOSIZE |SWP_NOMOVE);
|
||
|
}
|
||
|
else
|
||
|
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,SWP_NOSIZE |SWP_NOMOVE);
|
||
|
|
||
|
SetFocus(hWnd);
|
||
|
|
||
|
SetForegroundWindow(hWnd);
|
||
|
ShowWindow( hWnd, nCmdShow );
|
||
|
UpdateWindow( hWnd );
|
||
|
|
||
|
// save our application instance and window handle for future use
|
||
|
ApplicationHInstance = hInstance;
|
||
|
ApplicationHWnd = hWnd;
|
||
|
gInitializing = false;
|
||
|
if (!runWindowed) {
|
||
|
gDoPaint = false;
|
||
|
}
|
||
|
|
||
|
return true; // success
|
||
|
|
||
|
} // end initializeAppWindows
|
||
|
|
||
|
void munkeeFunc(void);
|
||
|
CDAPFN_DECLARE_GLOBAL(munkeeFunc, CDAPFN_OVERHEAD_L5, CDAPFN_CONSTRAINT_NONE);
|
||
|
void munkeeFunc(void)
|
||
|
{
|
||
|
CDAPFN_ENDMARK(munkeeFunc);
|
||
|
}
|
||
|
|
||
|
void checkProtection(void)
|
||
|
{
|
||
|
#ifdef _INTERNAL
|
||
|
__try
|
||
|
{
|
||
|
munkeeFunc();
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
exit(0); // someone is messing with us.
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// strtrim ====================================================================
|
||
|
/** Trim leading and trailing whitespace from a character string (in place). */
|
||
|
//=============================================================================
|
||
|
static char* strtrim(char* buffer)
|
||
|
{
|
||
|
if (buffer != NULL) {
|
||
|
// Strip leading white space from the string.
|
||
|
char * source = buffer;
|
||
|
while ((*source != 0) && ((unsigned char)*source <= 32))
|
||
|
{
|
||
|
source++;
|
||
|
}
|
||
|
|
||
|
if (source != buffer)
|
||
|
{
|
||
|
strcpy(buffer, source);
|
||
|
}
|
||
|
|
||
|
// Clip trailing white space from the string.
|
||
|
for (int index = strlen(buffer)-1; index >= 0; index--)
|
||
|
{
|
||
|
if ((*source != 0) && ((unsigned char)buffer[index] <= 32))
|
||
|
{
|
||
|
buffer[index] = '\0';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
char *nextParam(char *newSource, char *seps)
|
||
|
{
|
||
|
static char *source = NULL;
|
||
|
if (newSource)
|
||
|
{
|
||
|
source = newSource;
|
||
|
}
|
||
|
if (!source)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// find first separator
|
||
|
char *first = source;//strpbrk(source, seps);
|
||
|
if (first)
|
||
|
{
|
||
|
// go past separator
|
||
|
char *firstSep = strpbrk(first, seps);
|
||
|
char firstChar[2] = {0,0};
|
||
|
if (firstSep == first)
|
||
|
{
|
||
|
firstChar[0] = *first;
|
||
|
while (*first == firstChar[0]) first++;
|
||
|
}
|
||
|
|
||
|
// find end
|
||
|
char *end;
|
||
|
if (firstChar[0])
|
||
|
end = strpbrk(first, firstChar);
|
||
|
else
|
||
|
end = strpbrk(first, seps);
|
||
|
|
||
|
// trim string & save next start pos
|
||
|
if (end)
|
||
|
{
|
||
|
source = end+1;
|
||
|
*end = 0;
|
||
|
|
||
|
if (!*source)
|
||
|
source = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
source = NULL;
|
||
|
}
|
||
|
|
||
|
if (first && !*first)
|
||
|
first = NULL;
|
||
|
}
|
||
|
|
||
|
return first;
|
||
|
}
|
||
|
|
||
|
// Necessary to allow memory managers and such to have useful critical sections
|
||
|
static CriticalSection critSec1, critSec2, critSec3, critSec4, critSec5;
|
||
|
|
||
|
// WinMain ====================================================================
|
||
|
/** Application entry point */
|
||
|
//=============================================================================
|
||
|
Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||
|
LPSTR lpCmdLine, Int nCmdShow )
|
||
|
{
|
||
|
checkProtection();
|
||
|
|
||
|
try {
|
||
|
|
||
|
_set_se_translator( DumpExceptionInfo ); // Hook that allows stack trace.
|
||
|
//
|
||
|
// there is something about checkin in and out the .dsp and .dsw files
|
||
|
// that blows the working directory information away on each of the
|
||
|
// developers machines so we're going to hack it for a while and set our
|
||
|
// working directory to the directory with the .exe since that's not the
|
||
|
// default in a DevStudio project
|
||
|
//
|
||
|
|
||
|
TheAsciiStringCriticalSection = &critSec1;
|
||
|
TheUnicodeStringCriticalSection = &critSec2;
|
||
|
TheDmaCriticalSection = &critSec3;
|
||
|
TheMemoryPoolCriticalSection = &critSec4;
|
||
|
TheDebugLogCriticalSection = &critSec5;
|
||
|
|
||
|
/// @todo remove this force set of working directory later
|
||
|
Char buffer[ _MAX_PATH ];
|
||
|
GetModuleFileName( NULL, buffer, sizeof( buffer ) );
|
||
|
Char *pEnd = buffer + strlen( buffer );
|
||
|
while( pEnd != buffer )
|
||
|
{
|
||
|
if( *pEnd == '\\' )
|
||
|
{
|
||
|
*pEnd = 0;
|
||
|
break;
|
||
|
}
|
||
|
pEnd--;
|
||
|
}
|
||
|
::SetCurrentDirectory(buffer);
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Convert WinMain arguments to simple main argc and argv
|
||
|
*/
|
||
|
int argc = 1;
|
||
|
char * argv[20];
|
||
|
argv[0] = NULL;
|
||
|
|
||
|
char *token;
|
||
|
token = nextParam(lpCmdLine, "\" ");
|
||
|
while (argc < 20 && token != NULL) {
|
||
|
argv[argc++] = strtrim(token);
|
||
|
//added a preparse step for this flag because it affects window creation style
|
||
|
if (stricmp(token,"-win")==0)
|
||
|
ApplicationIsWindowed=true;
|
||
|
token = nextParam(NULL, "\" ");
|
||
|
}
|
||
|
|
||
|
if (argc>2 && strcmp(argv[1],"-DX")==0) {
|
||
|
Int i;
|
||
|
DEBUG_LOG(("\n--- DX STACK DUMP\n"));
|
||
|
for (i=2; i<argc; i++) {
|
||
|
Int pc;
|
||
|
pc = 0;
|
||
|
sscanf(argv[i], "%x", &pc);
|
||
|
char name[_MAX_PATH], file[_MAX_PATH];
|
||
|
unsigned int line;
|
||
|
unsigned int addr;
|
||
|
GetFunctionDetails((void*)pc, name, file, &line, &addr);
|
||
|
DEBUG_LOG(("0x%x - %s, %s, line %d address 0x%x\n", pc, name, file, line, addr));
|
||
|
}
|
||
|
DEBUG_LOG(("\n--- END OF DX STACK DUMP\n"));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
// Turn on Memory heap tracking
|
||
|
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
|
||
|
tmpFlag |= (_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
|
||
|
tmpFlag &= ~_CRTDBG_CHECK_CRT_DF;
|
||
|
_CrtSetDbgFlag( tmpFlag );
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
// install debug callbacks
|
||
|
// WWDebug_Install_Message_Handler(WWDebug_Message_Callback);
|
||
|
// WWDebug_Install_Assert_Handler(WWAssert_Callback);
|
||
|
|
||
|
// [SKB: Jun 24 2003 @ 1:50pm] :
|
||
|
// Force to be loaded from a file, not a resource so same exe can be used in germany and retail.
|
||
|
gLoadScreenBitmap = (HBITMAP)LoadImage(hInstance, "Install_Final.bmp", IMAGE_BITMAP, 0, 0, LR_SHARED|LR_LOADFROMFILE);
|
||
|
|
||
|
// register windows class and create application window
|
||
|
if( initializeAppWindows( hInstance, nCmdShow, ApplicationIsWindowed) == false )
|
||
|
return 0;
|
||
|
|
||
|
if (gLoadScreenBitmap!=NULL) {
|
||
|
::DeleteObject(gLoadScreenBitmap);
|
||
|
gLoadScreenBitmap = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// BGC - initialize COM
|
||
|
// OleInitialize(NULL);
|
||
|
|
||
|
// start the log
|
||
|
DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
|
||
|
initMemoryManager();
|
||
|
|
||
|
|
||
|
// Set up version info
|
||
|
TheVersion = NEW Version;
|
||
|
TheVersion->setVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_BUILDNUM, VERSION_LOCALBUILDNUM,
|
||
|
AsciiString(VERSION_BUILDUSER), AsciiString(VERSION_BUILDLOC),
|
||
|
AsciiString(__TIME__), AsciiString(__DATE__));
|
||
|
|
||
|
#ifdef DO_COPY_PROTECTION
|
||
|
if (!CopyProtect::isLauncherRunning())
|
||
|
{
|
||
|
DEBUG_LOG(("Launcher is not running - about to bail\n"));
|
||
|
delete TheVersion;
|
||
|
TheVersion = NULL;
|
||
|
shutdownMemoryManager();
|
||
|
DEBUG_SHUTDOWN();
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//Create a mutex with a unique name to Generals in order to determine if
|
||
|
//our app is already running.
|
||
|
//WARNING: DO NOT use this number for any other application except Generals.
|
||
|
GeneralsMutex = CreateMutex(NULL, FALSE, GENERALS_GUID);
|
||
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||
|
{
|
||
|
HWND ccwindow = FindWindow(GENERALS_GUID, NULL);
|
||
|
if (ccwindow)
|
||
|
{
|
||
|
SetForegroundWindow(ccwindow);
|
||
|
ShowWindow(ccwindow, SW_RESTORE);
|
||
|
}
|
||
|
if (GeneralsMutex != NULL)
|
||
|
{
|
||
|
CloseHandle(GeneralsMutex);
|
||
|
GeneralsMutex = NULL;
|
||
|
}
|
||
|
|
||
|
DEBUG_LOG(("Generals is already running...Bail!\n"));
|
||
|
delete TheVersion;
|
||
|
TheVersion = NULL;
|
||
|
shutdownMemoryManager();
|
||
|
DEBUG_SHUTDOWN();
|
||
|
return 0;
|
||
|
}
|
||
|
DEBUG_LOG(("Create GeneralsMutex okay.\n"));
|
||
|
|
||
|
#ifdef DO_COPY_PROTECTION
|
||
|
if (!CopyProtect::notifyLauncher())
|
||
|
{
|
||
|
DEBUG_LOG(("Could not talk to the launcher - about to bail\n"));
|
||
|
delete TheVersion;
|
||
|
TheVersion = NULL;
|
||
|
shutdownMemoryManager();
|
||
|
DEBUG_SHUTDOWN();
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
DEBUG_LOG(("CRC message is %d\n", GameMessage::MSG_LOGIC_CRC));
|
||
|
|
||
|
// run the game main loop
|
||
|
GameMain(argc, argv);
|
||
|
|
||
|
#ifdef DO_COPY_PROTECTION
|
||
|
// Clean up copy protection
|
||
|
CopyProtect::shutdown();
|
||
|
#endif
|
||
|
|
||
|
delete TheVersion;
|
||
|
TheVersion = NULL;
|
||
|
|
||
|
#ifdef MEMORYPOOL_DEBUG
|
||
|
TheMemoryPoolFactory->debugMemoryReport(REPORT_POOLINFO | REPORT_POOL_OVERFLOW | REPORT_SIMPLE_LEAKS, 0, 0);
|
||
|
#endif
|
||
|
#if defined(_DEBUG) || defined(_INTERNAL)
|
||
|
TheMemoryPoolFactory->memoryPoolUsageReport("AAAMemStats");
|
||
|
#endif
|
||
|
|
||
|
// close the log
|
||
|
shutdownMemoryManager();
|
||
|
DEBUG_SHUTDOWN();
|
||
|
|
||
|
// BGC - shut down COM
|
||
|
// OleUninitialize();
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
TheAsciiStringCriticalSection = NULL;
|
||
|
TheUnicodeStringCriticalSection = NULL;
|
||
|
TheDmaCriticalSection = NULL;
|
||
|
TheMemoryPoolCriticalSection = NULL;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} // end WinMain
|
||
|
|
||
|
// CreateGameEngine ===========================================================
|
||
|
/** Create the Win32 game engine we're going to use */
|
||
|
//=============================================================================
|
||
|
GameEngine *CreateGameEngine( void )
|
||
|
{
|
||
|
Win32GameEngine *engine;
|
||
|
|
||
|
engine = NEW Win32GameEngine;
|
||
|
//game engine may not have existed when app got focus so make sure it
|
||
|
//knows about current focus state.
|
||
|
engine->setIsActive(isWinMainActive);
|
||
|
|
||
|
return engine;
|
||
|
|
||
|
} // end CreateGameEngine
|