| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118 |
- /*
- ** Command & Conquer Generals Zero Hour(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/Registry.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"
- #include <rts/profile.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_QUERYENDSESSION:
- {
- TheMessageStream->appendMessage(GameMessage::MSG_META_DEMO_INSTANT_QUIT);
- return 0; //don't allow Windows to shutdown while game is running.
- }
- // ------------------------------------------------------------------------
- case WM_CLOSE:
- if (!TheGameEngine->getQuitting())
- {
- //user is exiting without using the menus
- //This method didn't work in cinematics because we don't process messages.
- //But it's the cleanest way to exit that's similar to using menus.
- TheMessageStream->appendMessage(GameMessage::MSG_META_DEMO_INSTANT_QUIT);
- //This method used to disable quitting. We just put up the options screen instead.
- //TheMessageStream->appendMessage(GameMessage::MSG_META_OPTIONS);
- //This method works everywhere but isn't as clean at shutting down.
- //TheGameEngine->checkAbnormalQuitting(); //old way to log disconnections for ALT-F4
- //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();
- #ifdef _PROFILE
- Profile::StartRange("init");
- #endif
- 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
- //
- 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);
- // Force "splash image" to be loaded from a file, not a resource so same exe can be used in different localizations.
- #if defined _DEBUG || defined _INTERNAL || defined _PROFILE
- // check both localized directory and root dir
- char filePath[_MAX_PATH];
- char *fileName = "Install_Final.bmp";
- static const char *localizedPathFormat = "Data/%s/";
- sprintf(filePath,localizedPathFormat, GetRegistryLanguage().str());
- strcat( filePath, fileName );
- FILE *fileImage = fopen(filePath, "r");
- if (fileImage) {
- fclose(fileImage);
- gLoadScreenBitmap = (HBITMAP)LoadImage(hInstance, filePath, IMAGE_BITMAP, 0, 0, LR_SHARED|LR_LOADFROMFILE);
- }
- else {
- gLoadScreenBitmap = (HBITMAP)LoadImage(hInstance, fileName, IMAGE_BITMAP, 0, 0, LR_SHARED|LR_LOADFROMFILE);
- }
- #else
-
- // in release, the file only ever lives in the root dir
- gLoadScreenBitmap = (HBITMAP)LoadImage(hInstance, "Install_Final.bmp", IMAGE_BITMAP, 0, 0, LR_SHARED|LR_LOADFROMFILE);
- #endif
- // 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 (...)
- {
-
- }
- 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
|