WinMain.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: WinMain.cpp //////////////////////////////////////////////////////////
  24. //
  25. // Entry point for game application
  26. //
  27. // Author: Colin Day, April 2001
  28. //
  29. ///////////////////////////////////////////////////////////////////////////////
  30. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  31. #define WIN32_LEAN_AND_MEAN // only bare bones windows stuff wanted
  32. #include <windows.h>
  33. #include <stdlib.h>
  34. #include <crtdbg.h>
  35. #include <eh.h>
  36. #include <ole2.h>
  37. #include <dbt.h>
  38. // USER INCLUDES //////////////////////////////////////////////////////////////
  39. #include "WinMain.h"
  40. #include "Lib/BaseType.h"
  41. #include "Common/CopyProtection.h"
  42. #include "Common/CriticalSection.h"
  43. #include "Common/GlobalData.h"
  44. #include "Common/GameEngine.h"
  45. #include "Common/GameSounds.h"
  46. #include "Common/Debug.h"
  47. #include "Common/GameMemory.h"
  48. #include "Common/SafeDisc/CdaPfn.h"
  49. #include "Common/StackDump.h"
  50. #include "Common/MessageStream.h"
  51. #include "Common/Team.h"
  52. #include "GameClient/InGameUI.h"
  53. #include "GameClient/GameClient.h"
  54. #include "GameLogic/GameLogic.h" ///< @todo for demo, remove
  55. #include "GameClient/Mouse.h"
  56. #include "GameClient/IMEManager.h"
  57. #include "Win32Device/GameClient/Win32Mouse.h"
  58. #include "Win32Device/Common/Win32GameEngine.h"
  59. #include "Common/Version.h"
  60. #include "BuildVersion.h"
  61. #include "GeneratedVersion.h"
  62. #include "Resource.h"
  63. #ifdef _INTERNAL
  64. // for occasional debugging...
  65. //#pragma optimize("", off)
  66. //#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
  67. #endif
  68. // GLOBALS ////////////////////////////////////////////////////////////////////
  69. HINSTANCE ApplicationHInstance = NULL; ///< our application instance
  70. HWND ApplicationHWnd = NULL; ///< our application window handle
  71. Bool ApplicationIsWindowed = false;
  72. Win32Mouse *TheWin32Mouse= NULL; ///< for the WndProc() only
  73. DWORD TheMessageTime = 0; ///< For getting the time that a message was posted from Windows.
  74. const Char *g_strFile = "data\\Generals.str";
  75. const Char *g_csfFile = "data\\%s\\Generals.csf";
  76. char *gAppPrefix = ""; /// So WB can have a different debug log file name.
  77. static HANDLE GeneralsMutex = NULL;
  78. #define GENERALS_GUID "685EAFF2-3216-4265-B047-251C5F4B82F3"
  79. #define DEFAULT_XRESOLUTION 800
  80. #define DEFAULT_YRESOLUTION 600
  81. extern void Reset_D3D_Device(bool active);
  82. static Bool gInitializing = false;
  83. static Bool gDoPaint = true;
  84. static Bool isWinMainActive = false;
  85. static HBITMAP gLoadScreenBitmap = NULL;
  86. //#define DEBUG_WINDOWS_MESSAGES
  87. #ifdef DEBUG_WINDOWS_MESSAGES
  88. static const char *messageToString(unsigned int message)
  89. {
  90. static char name[32];
  91. switch (message)
  92. {
  93. case WM_NULL: return "WM_NULL";
  94. case WM_CREATE: return "WM_CREATE";
  95. case WM_DESTROY: return "WM_DESTROY";
  96. case WM_MOVE: return "WM_MOVE";
  97. case WM_SIZE: return "WM_SIZE";
  98. case WM_ACTIVATE: return "WM_ACTIVATE";
  99. case WM_SETFOCUS: return "WM_SETFOCUS";
  100. case WM_KILLFOCUS: return "WM_KILLFOCUS";
  101. case WM_ENABLE: return "WM_ENABLE";
  102. case WM_SETREDRAW: return "WM_SETREDRAW";
  103. case WM_SETTEXT: return "WM_SETTEXT";
  104. case WM_GETTEXT: return "WM_GETTEXT";
  105. case WM_GETTEXTLENGTH: return "WM_GETTEXTLENGTH";
  106. case WM_PAINT: return "WM_PAINT";
  107. case WM_CLOSE: return "WM_CLOSE";
  108. case WM_QUERYENDSESSION: return "WM_QUERYENDSESSION";
  109. case WM_QUIT: return "WM_QUIT";
  110. case WM_QUERYOPEN: return "WM_QUERYOPEN";
  111. case WM_ERASEBKGND: return "WM_ERASEBKGND";
  112. case WM_SYSCOLORCHANGE: return "WM_SYSCOLORCHANGE";
  113. case WM_ENDSESSION: return "WM_ENDSESSION";
  114. case WM_SHOWWINDOW: return "WM_SHOWWINDOW";
  115. case WM_WININICHANGE: return "WM_WININICHANGE";
  116. case WM_DEVMODECHANGE: return "WM_DEVMODECHANGE";
  117. case WM_ACTIVATEAPP: return "WM_ACTIVATEAPP";
  118. case WM_FONTCHANGE: return "WM_FONTCHANGE";
  119. case WM_TIMECHANGE: return "WM_TIMECHANGE";
  120. case WM_CANCELMODE: return "WM_CANCELMODE";
  121. case WM_SETCURSOR: return "WM_SETCURSOR";
  122. case WM_MOUSEACTIVATE: return "WM_MOUSEACTIVATE";
  123. case WM_CHILDACTIVATE: return "WM_CHILDACTIVATE";
  124. case WM_QUEUESYNC: return "WM_QUEUESYNC";
  125. case WM_GETMINMAXINFO: return "WM_GETMINMAXINFO";
  126. case WM_PAINTICON: return "WM_PAINTICON";
  127. case WM_ICONERASEBKGND: return "WM_ICONERASEBKGND";
  128. case WM_NEXTDLGCTL: return "WM_NEXTDLGCTL";
  129. case WM_SPOOLERSTATUS: return "WM_SPOOLERSTATUS";
  130. case WM_DRAWITEM: return "WM_DRAWITEM";
  131. case WM_MEASUREITEM: return "WM_MEASUREITEM";
  132. case WM_DELETEITEM: return "WM_DELETEITEM";
  133. case WM_VKEYTOITEM: return "WM_VKEYTOITEM";
  134. case WM_CHARTOITEM: return "WM_CHARTOITEM";
  135. case WM_SETFONT: return "WM_SETFONT";
  136. case WM_GETFONT: return "WM_GETFONT";
  137. case WM_SETHOTKEY: return "WM_SETHOTKEY";
  138. case WM_GETHOTKEY: return "WM_GETHOTKEY";
  139. case WM_QUERYDRAGICON: return "WM_QUERYDRAGICON";
  140. case WM_COMPAREITEM: return "WM_COMPAREITEM";
  141. case WM_COMPACTING: return "WM_COMPACTING";
  142. case WM_COMMNOTIFY: return "WM_COMMNOTIFY";
  143. case WM_WINDOWPOSCHANGING: return "WM_WINDOWPOSCHANGING";
  144. case WM_WINDOWPOSCHANGED: return "WM_WINDOWPOSCHANGED";
  145. case WM_POWER: return "WM_POWER";
  146. case WM_COPYDATA: return "WM_COPYDATA";
  147. case WM_CANCELJOURNAL: return "WM_CANCELJOURNAL";
  148. case WM_NOTIFY: return "WM_NOTIFY";
  149. case WM_INPUTLANGCHANGEREQUEST: return "WM_INPUTLANGCHANGEREQUES";
  150. case WM_INPUTLANGCHANGE: return "WM_INPUTLANGCHANGE";
  151. case WM_TCARD: return "WM_TCARD";
  152. case WM_HELP: return "WM_HELP";
  153. case WM_USERCHANGED: return "WM_USERCHANGED";
  154. case WM_NOTIFYFORMAT: return "WM_NOTIFYFORMAT";
  155. case WM_CONTEXTMENU: return "WM_CONTEXTMENU";
  156. case WM_STYLECHANGING: return "WM_STYLECHANGING";
  157. case WM_STYLECHANGED: return "WM_STYLECHANGED";
  158. case WM_DISPLAYCHANGE: return "WM_DISPLAYCHANGE";
  159. case WM_GETICON: return "WM_GETICON";
  160. case WM_SETICON: return "WM_SETICON";
  161. case WM_NCCREATE: return "WM_NCCREATE";
  162. case WM_NCDESTROY: return "WM_NCDESTROY";
  163. case WM_NCCALCSIZE: return "WM_NCCALCSIZE";
  164. case WM_NCHITTEST: return "WM_NCHITTEST";
  165. case WM_NCPAINT: return "WM_NCPAINT";
  166. case WM_NCACTIVATE: return "WM_NCACTIVATE";
  167. case WM_GETDLGCODE: return "WM_GETDLGCODE";
  168. case WM_SYNCPAINT: return "WM_SYNCPAINT";
  169. case WM_NCMOUSEMOVE: return "WM_NCMOUSEMOVE";
  170. case WM_NCLBUTTONDOWN: return "WM_NCLBUTTONDOWN";
  171. case WM_NCLBUTTONUP: return "WM_NCLBUTTONUP";
  172. case WM_NCLBUTTONDBLCLK: return "WM_NCLBUTTONDBLCLK";
  173. case WM_NCRBUTTONDOWN: return "WM_NCRBUTTONDOWN";
  174. case WM_NCRBUTTONUP: return "WM_NCRBUTTONUP";
  175. case WM_NCRBUTTONDBLCLK: return "WM_NCRBUTTONDBLCLK";
  176. case WM_NCMBUTTONDOWN: return "WM_NCMBUTTONDOWN";
  177. case WM_NCMBUTTONUP: return "WM_NCMBUTTONUP";
  178. case WM_NCMBUTTONDBLCLK: return "WM_NCMBUTTONDBLCLK";
  179. case WM_KEYDOWN: return "WM_KEYDOWN";
  180. case WM_KEYUP: return "WM_KEYUP";
  181. case WM_CHAR: return "WM_CHAR";
  182. case WM_DEADCHAR: return "WM_DEADCHAR";
  183. case WM_SYSKEYDOWN: return "WM_SYSKEYDOWN";
  184. case WM_SYSKEYUP: return "WM_SYSKEYUP";
  185. case WM_SYSCHAR: return "WM_SYSCHAR";
  186. case WM_SYSDEADCHAR: return "WM_SYSDEADCHAR";
  187. case WM_KEYLAST: return "WM_KEYLAST";
  188. case WM_IME_STARTCOMPOSITION: return "WM_IME_STARTCOMPOSITION";
  189. case WM_IME_ENDCOMPOSITION: return "WM_IME_ENDCOMPOSITION";
  190. case WM_IME_COMPOSITION: return "WM_IME_COMPOSITION";
  191. case WM_INITDIALOG: return "WM_INITDIALOG";
  192. case WM_COMMAND: return "WM_COMMAND";
  193. case WM_SYSCOMMAND: return "WM_SYSCOMMAND";
  194. case WM_TIMER: return "WM_TIMER";
  195. case WM_HSCROLL: return "WM_HSCROLL";
  196. case WM_VSCROLL: return "WM_VSCROLL";
  197. case WM_INITMENU: return "WM_INITMENU";
  198. case WM_INITMENUPOPUP: return "WM_INITMENUPOPUP";
  199. case WM_MENUSELECT: return "WM_MENUSELECT";
  200. case WM_MENUCHAR: return "WM_MENUCHAR";
  201. case WM_ENTERIDLE: return "WM_ENTERIDLE";
  202. case WM_CTLCOLORMSGBOX: return "WM_CTLCOLORMSGBOX";
  203. case WM_CTLCOLOREDIT: return "WM_CTLCOLOREDIT";
  204. case WM_CTLCOLORLISTBOX: return "WM_CTLCOLORLISTBOX";
  205. case WM_CTLCOLORBTN: return "WM_CTLCOLORBTN";
  206. case WM_CTLCOLORDLG: return "WM_CTLCOLORDLG";
  207. case WM_CTLCOLORSCROLLBAR: return "WM_CTLCOLORSCROLLBAR";
  208. case WM_CTLCOLORSTATIC: return "WM_CTLCOLORSTATIC";
  209. case WM_MOUSEMOVE: return "WM_MOUSEMOVE";
  210. case WM_LBUTTONDOWN: return "WM_LBUTTONDOWN";
  211. case WM_LBUTTONUP: return "WM_LBUTTONUP";
  212. case WM_LBUTTONDBLCLK: return "WM_LBUTTONDBLCLK";
  213. case WM_RBUTTONDOWN: return "WM_RBUTTONDOWN";
  214. case WM_RBUTTONUP: return "WM_RBUTTONUP";
  215. case WM_RBUTTONDBLCLK: return "WM_RBUTTONDBLCLK";
  216. case WM_MBUTTONDOWN: return "WM_MBUTTONDOWN";
  217. case WM_MBUTTONUP: return "WM_MBUTTONUP";
  218. case WM_MBUTTONDBLCLK: return "WM_MBUTTONDBLCLK";
  219. // case WM_MOUSEWHEEL: return "WM_MOUSEWHEEL";
  220. case WM_PARENTNOTIFY: return "WM_PARENTNOTIFY";
  221. case WM_ENTERMENULOOP: return "WM_ENTERMENULOOP";
  222. case WM_EXITMENULOOP: return "WM_EXITMENULOOP";
  223. case WM_NEXTMENU: return "WM_NEXTMENU";
  224. case WM_SIZING: return "WM_SIZING";
  225. case WM_CAPTURECHANGED: return "WM_CAPTURECHANGED";
  226. case WM_MOVING: return "WM_MOVING";
  227. case WM_POWERBROADCAST: return "WM_POWERBROADCAST";
  228. case WM_DEVICECHANGE: return "WM_DEVICECHANGE";
  229. case WM_MDICREATE: return "WM_MDICREATE";
  230. case WM_MDIDESTROY: return "WM_MDIDESTROY";
  231. case WM_MDIACTIVATE: return "WM_MDIACTIVATE";
  232. case WM_MDIRESTORE: return "WM_MDIRESTORE";
  233. case WM_MDINEXT: return "WM_MDINEXT";
  234. case WM_MDIMAXIMIZE: return "WM_MDIMAXIMIZE";
  235. case WM_MDITILE: return "WM_MDITILE";
  236. case WM_MDICASCADE: return "WM_MDICASCADE";
  237. case WM_MDIICONARRANGE: return "WM_MDIICONARRANGE";
  238. case WM_MDIGETACTIVE: return "WM_MDIGETACTIVE";
  239. case WM_MDISETMENU: return "WM_MDISETMENU";
  240. case WM_ENTERSIZEMOVE: return "WM_ENTERSIZEMOVE";
  241. case WM_EXITSIZEMOVE: return "WM_EXITSIZEMOVE";
  242. case WM_DROPFILES: return "WM_DROPFILES";
  243. case WM_MDIREFRESHMENU: return "WM_MDIREFRESHMENU";
  244. case WM_IME_SETCONTEXT: return "WM_IME_SETCONTEXT";
  245. case WM_IME_NOTIFY: return "WM_IME_NOTIFY";
  246. case WM_IME_CONTROL: return "WM_IME_CONTROL";
  247. case WM_IME_COMPOSITIONFULL: return "WM_IME_COMPOSITIONFULL";
  248. case WM_IME_SELECT: return "WM_IME_SELECT";
  249. case WM_IME_CHAR: return "WM_IME_CHAR";
  250. case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN";
  251. case WM_IME_KEYUP: return "WM_IME_KEYUP";
  252. // case WM_MOUSEHOVER: return "WM_MOUSEHOVER";
  253. // case WM_MOUSELEAVE: return "WM_MOUSELEAVE";
  254. case WM_CUT: return "WM_CUT";
  255. case WM_COPY: return "WM_COPY";
  256. case WM_PASTE: return "WM_PASTE";
  257. case WM_CLEAR: return "WM_CLEAR";
  258. case WM_UNDO: return "WM_UNDO";
  259. case WM_RENDERFORMAT: return "WM_RENDERFORMAT";
  260. case WM_RENDERALLFORMATS: return "WM_RENDERALLFORMATS";
  261. case WM_DESTROYCLIPBOARD: return "WM_DESTROYCLIPBOARD";
  262. case WM_DRAWCLIPBOARD: return "WM_DRAWCLIPBOARD";
  263. case WM_PAINTCLIPBOARD: return "WM_PAINTCLIPBOARD";
  264. case WM_VSCROLLCLIPBOARD: return "WM_VSCROLLCLIPBOARD";
  265. case WM_SIZECLIPBOARD: return "WM_SIZECLIPBOARD";
  266. case WM_ASKCBFORMATNAME: return "WM_ASKCBFORMATNAME";
  267. case WM_CHANGECBCHAIN: return "WM_CHANGECBCHAIN";
  268. case WM_HSCROLLCLIPBOARD: return "WM_HSCROLLCLIPBOARD";
  269. case WM_QUERYNEWPALETTE: return "WM_QUERYNEWPALETTE";
  270. case WM_PALETTEISCHANGING: return "WM_PALETTEISCHANGING";
  271. case WM_PALETTECHANGED: return "WM_PALETTECHANGED";
  272. case WM_HOTKEY: return "WM_HOTKEY";
  273. case WM_PRINT: return "WM_PRINT";
  274. case WM_PRINTCLIENT: return "WM_PRINTCLIENT";
  275. case WM_HANDHELDFIRST: return "WM_HANDHELDFIRST";
  276. case WM_HANDHELDLAST: return "WM_HANDHELDLAST";
  277. case WM_AFXFIRST: return "WM_AFXFIRST";
  278. case WM_AFXLAST: return "WM_AFXLAST";
  279. case WM_PENWINFIRST: return "WM_PENWINFIRST";
  280. case WM_PENWINLAST: return "WM_PENWINLAST";
  281. default: return "WM_UNKNOWN";
  282. };
  283. }
  284. #endif
  285. // WndProc ====================================================================
  286. /** Window Procedure */
  287. //=============================================================================
  288. LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
  289. WPARAM wParam, LPARAM lParam )
  290. {
  291. try
  292. {
  293. // First let the IME manager do it's stuff.
  294. if ( TheIMEManager )
  295. {
  296. if ( TheIMEManager->serviceIMEMessage( hWnd, message, wParam, lParam ) )
  297. {
  298. // The manager intercepted an IME message so return the result
  299. return TheIMEManager->result();
  300. }
  301. }
  302. #ifdef DO_COPY_PROTECTION
  303. // Check for messages from the launcher
  304. CopyProtect::checkForMessage(message, lParam);
  305. #endif
  306. #ifdef DEBUG_WINDOWS_MESSAGES
  307. static msgCount=0;
  308. char testString[256];
  309. sprintf(testString,"\n%d: %s (%X,%X)", msgCount++,messageToString(message), wParam, lParam);
  310. OutputDebugString(testString);
  311. #endif
  312. // handle all window messages
  313. switch( message )
  314. {
  315. //-------------------------------------------------------------------------
  316. case WM_NCHITTEST:
  317. // Prevent the user from selecting the menu in fullscreen mode
  318. if( !ApplicationIsWindowed )
  319. return HTCLIENT;
  320. break;
  321. //-------------------------------------------------------------------------
  322. case WM_POWERBROADCAST:
  323. switch( wParam )
  324. {
  325. #ifndef PBT_APMQUERYSUSPEND
  326. #define PBT_APMQUERYSUSPEND 0x0000
  327. #endif
  328. case PBT_APMQUERYSUSPEND:
  329. // At this point, the app should save any data for open
  330. // network connections, files, etc., and prepare to go into
  331. // a suspended mode.
  332. return TRUE;
  333. #ifndef PBT_APMRESUMESUSPEND
  334. #define PBT_APMRESUMESUSPEND 0x0007
  335. #endif
  336. case PBT_APMRESUMESUSPEND:
  337. // At this point, the app should recover any data, network
  338. // connections, files, etc., and resume running from when
  339. // the app was suspended.
  340. return TRUE;
  341. }
  342. break;
  343. //-------------------------------------------------------------------------
  344. case WM_SYSCOMMAND:
  345. // Prevent moving/sizing and power loss in fullscreen mode
  346. switch( wParam )
  347. {
  348. case SC_MOVE:
  349. case SC_SIZE:
  350. case SC_MAXIMIZE:
  351. case SC_KEYMENU:
  352. case SC_MONITORPOWER:
  353. if( FALSE == ApplicationIsWindowed )
  354. return 1;
  355. break;
  356. }
  357. break;
  358. // ------------------------------------------------------------------------
  359. case WM_CLOSE:
  360. TheGameEngine->checkAbnormalQuitting();
  361. TheGameEngine->reset();
  362. TheGameEngine->setQuitting(TRUE);
  363. _exit(EXIT_SUCCESS);
  364. return 0;
  365. // ------------------------------------------------------------------------
  366. case WM_SETFOCUS:
  367. {
  368. //
  369. // reset the state of our keyboard cause we haven't been paying
  370. // attention to the keys while focus was away
  371. //
  372. if( TheKeyboard )
  373. TheKeyboard->resetKeys();
  374. if (TheWin32Mouse)
  375. TheWin32Mouse->lostFocus(FALSE);
  376. break;
  377. } // end set focus
  378. //-------------------------------------------------------------------------
  379. case WM_SIZE:
  380. // When W3D initializes, it resizes the window. So stop repainting.
  381. if (!gInitializing)
  382. gDoPaint = false;
  383. break;
  384. //-------------------------------------------------------------------------
  385. case WM_KILLFOCUS:
  386. {
  387. if (TheKeyboard )
  388. TheKeyboard->resetKeys();
  389. if (TheWin32Mouse)
  390. TheWin32Mouse->lostFocus(TRUE);
  391. break;
  392. }
  393. //-------------------------------------------------------------------------
  394. case WM_ACTIVATEAPP:
  395. {
  396. // DWORD threadId=GetCurrentThreadId();
  397. if ((bool) wParam != isWinMainActive)
  398. { isWinMainActive = (BOOL) wParam;
  399. if (TheGameEngine)
  400. TheGameEngine->setIsActive(isWinMainActive);
  401. Reset_D3D_Device(isWinMainActive);
  402. if (isWinMainActive)
  403. { //restore mouse cursor to our custom version.
  404. if (TheWin32Mouse)
  405. TheWin32Mouse->setCursor(TheWin32Mouse->getMouseCursor());
  406. }
  407. }
  408. return 0;
  409. }
  410. //-------------------------------------------------------------------------
  411. case WM_ACTIVATE:
  412. {
  413. Int active = LOWORD( wParam );
  414. //
  415. // when window is becoming deactivated we must release mouse cursor
  416. // locks on our region, otherwise set the mouse limit region again
  417. // which will clip the cursor to our window
  418. //
  419. if( active == WA_INACTIVE )
  420. {
  421. ClipCursor( NULL );
  422. if (TheAudio)
  423. TheAudio->loseFocus();
  424. } // end if
  425. else
  426. {
  427. if( TheMouse )
  428. TheMouse->setMouseLimits();
  429. if (TheAudio)
  430. TheAudio->regainFocus();
  431. } // end else
  432. break;
  433. } // end case activate
  434. //-------------------------------------------------------------------------
  435. case WM_KEYDOWN:
  436. {
  437. Int key = (Int)wParam;
  438. switch( key )
  439. {
  440. //---------------------------------------------------------------------
  441. case VK_ESCAPE:
  442. {
  443. PostQuitMessage( 0 );
  444. break;
  445. } // end VK_ESCAPE
  446. } // end switch
  447. return 0;
  448. } // end WM_KEYDOWN
  449. //-------------------------------------------------------------------------
  450. case WM_LBUTTONDOWN:
  451. case WM_LBUTTONUP:
  452. case WM_LBUTTONDBLCLK:
  453. case WM_MBUTTONDOWN:
  454. case WM_MBUTTONUP:
  455. case WM_MBUTTONDBLCLK:
  456. case WM_RBUTTONDOWN:
  457. case WM_RBUTTONUP:
  458. case WM_RBUTTONDBLCLK:
  459. {
  460. if( TheWin32Mouse )
  461. TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
  462. return 0;
  463. } // end WM_LBUTTONDOWN
  464. //-------------------------------------------------------------------------
  465. case 0x020A: // WM_MOUSEWHEEL
  466. {
  467. long x = (long) LOWORD(lParam);
  468. long y = (long) HIWORD(lParam);
  469. RECT rect;
  470. // ignore when outside of client area
  471. GetWindowRect( ApplicationHWnd, &rect );
  472. if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom )
  473. return 0;
  474. if( TheWin32Mouse )
  475. TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
  476. return 0;
  477. } // end WM_MOUSEWHEEL
  478. //-------------------------------------------------------------------------
  479. case WM_MOUSEMOVE:
  480. {
  481. Int x = (Int)LOWORD( lParam );
  482. Int y = (Int)HIWORD( lParam );
  483. RECT rect;
  484. // Int keys = wParam;
  485. // ignore when outside of client area
  486. GetClientRect( ApplicationHWnd, &rect );
  487. if( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom )
  488. return 0;
  489. if( TheWin32Mouse )
  490. TheWin32Mouse->addWin32Event( message, wParam, lParam, TheMessageTime );
  491. return 0;
  492. } // end WM_MOUSEMOVE
  493. //-------------------------------------------------------------------------
  494. case WM_SETCURSOR:
  495. {
  496. if (TheWin32Mouse && (HWND)wParam == ApplicationHWnd)
  497. TheWin32Mouse->setCursor(TheWin32Mouse->getMouseCursor());
  498. return TRUE; //tell Windows not to reset mouse cursor image to default.
  499. }
  500. case WM_PAINT:
  501. {
  502. if (gDoPaint) {
  503. PAINTSTRUCT paint;
  504. HDC dc = ::BeginPaint(hWnd, &paint);
  505. #if 0
  506. ::SetTextColor(dc, RGB(255,255,255));
  507. ::SetBkColor(dc, RGB(0,0,0));
  508. ::TextOut(dc, 30, 30, "Loading Command & Conquer Generals...", 37);
  509. #endif
  510. if (gLoadScreenBitmap!=NULL) {
  511. Int savContext = ::SaveDC(dc);
  512. HDC tmpDC = ::CreateCompatibleDC(dc);
  513. HBITMAP savBitmap = (HBITMAP)::SelectObject(tmpDC, gLoadScreenBitmap);
  514. ::BitBlt(dc, 0, 0, DEFAULT_XRESOLUTION, DEFAULT_YRESOLUTION, tmpDC, 0, 0, SRCCOPY);
  515. ::SelectObject(tmpDC, savBitmap);
  516. ::DeleteDC(tmpDC);
  517. ::RestoreDC(dc, savContext);
  518. }
  519. ::EndPaint(hWnd, &paint);
  520. return TRUE;
  521. }
  522. break;
  523. }
  524. case WM_ERASEBKGND:
  525. {
  526. if (!gDoPaint)
  527. return TRUE; //we don't need to erase the background because we always draw entire window.
  528. break;
  529. }
  530. // Well, it was a nice idea, but we don't get a message for an ejection.
  531. // (Really unforunate, actually.) I'm leaving this in in-case some one wants
  532. // to trap a different device change (for instance, removal of a mouse) - jkmcd
  533. #if 0
  534. case WM_DEVICECHANGE:
  535. {
  536. if (((UINT) wParam) == DBT_DEVICEREMOVEPENDING)
  537. {
  538. DEV_BROADCAST_HDR *hdr = (DEV_BROADCAST_HDR*) lParam;
  539. if (!hdr) {
  540. break;
  541. }
  542. if (hdr->dbch_devicetype != DBT_DEVTYP_VOLUME) {
  543. break;
  544. }
  545. // Lets discuss how Windows is a flaming pile of poo. I'm now casting the header
  546. // directly into the structure, because its the one I want, and this is just how
  547. // its done. I hate Windows. - jkmcd
  548. DEV_BROADCAST_VOLUME *vol = (DEV_BROADCAST_VOLUME*) (hdr);
  549. // @todo - Yikes. This could cause us all kinds of pain. I don't really want
  550. // to even think about the stink this could cause us.
  551. TheFileSystem->unloadMusicFilesFromCD(vol->dbcv_unitmask);
  552. return TRUE;
  553. }
  554. break;
  555. }
  556. #endif
  557. } // end switch
  558. }
  559. catch (...)
  560. {
  561. RELEASE_CRASH(("Uncaught exception in Main::WndProc... probably should not happen\n"));
  562. // no rethrow
  563. }
  564. //In full-screen mode, only pass these messages onto the default windows handler.
  565. //Appears to fix issues with dual monitor systems but doesn't seem safe?
  566. ///@todo: Look into proper support for dual monitor systems.
  567. /* if (!ApplicationIsWindowed)
  568. switch (message)
  569. {
  570. case WM_PAINT:
  571. case WM_NCCREATE:
  572. case WM_NCDESTROY:
  573. case WM_NCCALCSIZE:
  574. case WM_NCPAINT:
  575. return DefWindowProc( hWnd, message, wParam, lParam );
  576. }
  577. return 0;*/
  578. return DefWindowProc( hWnd, message, wParam, lParam );
  579. } // end WndProc
  580. // initializeAppWindows =======================================================
  581. /** Register windows class and create application windows. */
  582. //=============================================================================
  583. static Bool initializeAppWindows( HINSTANCE hInstance, Int nCmdShow, Bool runWindowed )
  584. {
  585. DWORD windowStyle;
  586. Int startWidth = DEFAULT_XRESOLUTION,
  587. startHeight = DEFAULT_YRESOLUTION;
  588. // register the window class
  589. WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, WndProc, 0, 0, hInstance,
  590. LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ApplicationIcon)),
  591. NULL/*LoadCursor(NULL, IDC_ARROW)*/,
  592. (HBRUSH)GetStockObject(BLACK_BRUSH), NULL,
  593. TEXT("Game Window") };
  594. RegisterClass( &wndClass );
  595. // Create our main window
  596. windowStyle = WS_POPUP|WS_VISIBLE;
  597. if (runWindowed)
  598. windowStyle |= WS_DLGFRAME | WS_CAPTION | WS_SYSMENU;
  599. else
  600. windowStyle |= WS_EX_TOPMOST | WS_SYSMENU;
  601. RECT rect;
  602. rect.left = 0;
  603. rect.top = 0;
  604. rect.right = startWidth;
  605. rect.bottom = startHeight;
  606. AdjustWindowRect (&rect, windowStyle, FALSE);
  607. if (runWindowed) {
  608. // Makes the normal debug 800x600 window center in the screen.
  609. startWidth = DEFAULT_XRESOLUTION;
  610. startHeight= DEFAULT_YRESOLUTION;
  611. }
  612. gInitializing = true;
  613. HWND hWnd = CreateWindow( TEXT("Game Window"),
  614. TEXT("Command and Conquer Generals"),
  615. windowStyle,
  616. (GetSystemMetrics( SM_CXSCREEN ) / 2) - (startWidth / 2), // original position X
  617. (GetSystemMetrics( SM_CYSCREEN ) / 2) - (startHeight / 2),// original position Y
  618. // Lorenzen nudged the window higher
  619. // so the constantdebug report would
  620. // not get obliterated by assert windows, thank you.
  621. //(GetSystemMetrics( SM_CXSCREEN ) / 2) - (startWidth / 2), //this works with any screen res
  622. //(GetSystemMetrics( SM_CYSCREEN ) / 25) - (startHeight / 25),//this works with any screen res
  623. rect.right-rect.left,
  624. rect.bottom-rect.top,
  625. 0L,
  626. 0L,
  627. hInstance,
  628. 0L );
  629. if (!runWindowed)
  630. { SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,SWP_NOSIZE |SWP_NOMOVE);
  631. }
  632. else
  633. SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,SWP_NOSIZE |SWP_NOMOVE);
  634. SetFocus(hWnd);
  635. SetForegroundWindow(hWnd);
  636. ShowWindow( hWnd, nCmdShow );
  637. UpdateWindow( hWnd );
  638. // save our application instance and window handle for future use
  639. ApplicationHInstance = hInstance;
  640. ApplicationHWnd = hWnd;
  641. gInitializing = false;
  642. if (!runWindowed) {
  643. gDoPaint = false;
  644. }
  645. return true; // success
  646. } // end initializeAppWindows
  647. void munkeeFunc(void);
  648. CDAPFN_DECLARE_GLOBAL(munkeeFunc, CDAPFN_OVERHEAD_L5, CDAPFN_CONSTRAINT_NONE);
  649. void munkeeFunc(void)
  650. {
  651. CDAPFN_ENDMARK(munkeeFunc);
  652. }
  653. void checkProtection(void)
  654. {
  655. #ifdef _INTERNAL
  656. __try
  657. {
  658. munkeeFunc();
  659. }
  660. __except(EXCEPTION_EXECUTE_HANDLER)
  661. {
  662. exit(0); // someone is messing with us.
  663. }
  664. #endif
  665. }
  666. // strtrim ====================================================================
  667. /** Trim leading and trailing whitespace from a character string (in place). */
  668. //=============================================================================
  669. static char* strtrim(char* buffer)
  670. {
  671. if (buffer != NULL) {
  672. // Strip leading white space from the string.
  673. char * source = buffer;
  674. while ((*source != 0) && ((unsigned char)*source <= 32))
  675. {
  676. source++;
  677. }
  678. if (source != buffer)
  679. {
  680. strcpy(buffer, source);
  681. }
  682. // Clip trailing white space from the string.
  683. for (int index = strlen(buffer)-1; index >= 0; index--)
  684. {
  685. if ((*source != 0) && ((unsigned char)buffer[index] <= 32))
  686. {
  687. buffer[index] = '\0';
  688. }
  689. else
  690. {
  691. break;
  692. }
  693. }
  694. }
  695. return buffer;
  696. }
  697. char *nextParam(char *newSource, char *seps)
  698. {
  699. static char *source = NULL;
  700. if (newSource)
  701. {
  702. source = newSource;
  703. }
  704. if (!source)
  705. {
  706. return NULL;
  707. }
  708. // find first separator
  709. char *first = source;//strpbrk(source, seps);
  710. if (first)
  711. {
  712. // go past separator
  713. char *firstSep = strpbrk(first, seps);
  714. char firstChar[2] = {0,0};
  715. if (firstSep == first)
  716. {
  717. firstChar[0] = *first;
  718. while (*first == firstChar[0]) first++;
  719. }
  720. // find end
  721. char *end;
  722. if (firstChar[0])
  723. end = strpbrk(first, firstChar);
  724. else
  725. end = strpbrk(first, seps);
  726. // trim string & save next start pos
  727. if (end)
  728. {
  729. source = end+1;
  730. *end = 0;
  731. if (!*source)
  732. source = NULL;
  733. }
  734. else
  735. {
  736. source = NULL;
  737. }
  738. if (first && !*first)
  739. first = NULL;
  740. }
  741. return first;
  742. }
  743. // Necessary to allow memory managers and such to have useful critical sections
  744. static CriticalSection critSec1, critSec2, critSec3, critSec4, critSec5;
  745. // WinMain ====================================================================
  746. /** Application entry point */
  747. //=============================================================================
  748. Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  749. LPSTR lpCmdLine, Int nCmdShow )
  750. {
  751. checkProtection();
  752. try {
  753. _set_se_translator( DumpExceptionInfo ); // Hook that allows stack trace.
  754. //
  755. // there is something about checkin in and out the .dsp and .dsw files
  756. // that blows the working directory information away on each of the
  757. // developers machines so we're going to hack it for a while and set our
  758. // working directory to the directory with the .exe since that's not the
  759. // default in a DevStudio project
  760. //
  761. TheAsciiStringCriticalSection = &critSec1;
  762. TheUnicodeStringCriticalSection = &critSec2;
  763. TheDmaCriticalSection = &critSec3;
  764. TheMemoryPoolCriticalSection = &critSec4;
  765. TheDebugLogCriticalSection = &critSec5;
  766. /// @todo remove this force set of working directory later
  767. Char buffer[ _MAX_PATH ];
  768. GetModuleFileName( NULL, buffer, sizeof( buffer ) );
  769. Char *pEnd = buffer + strlen( buffer );
  770. while( pEnd != buffer )
  771. {
  772. if( *pEnd == '\\' )
  773. {
  774. *pEnd = 0;
  775. break;
  776. }
  777. pEnd--;
  778. }
  779. ::SetCurrentDirectory(buffer);
  780. /*
  781. ** Convert WinMain arguments to simple main argc and argv
  782. */
  783. int argc = 1;
  784. char * argv[20];
  785. argv[0] = NULL;
  786. char *token;
  787. token = nextParam(lpCmdLine, "\" ");
  788. while (argc < 20 && token != NULL) {
  789. argv[argc++] = strtrim(token);
  790. //added a preparse step for this flag because it affects window creation style
  791. if (stricmp(token,"-win")==0)
  792. ApplicationIsWindowed=true;
  793. token = nextParam(NULL, "\" ");
  794. }
  795. if (argc>2 && strcmp(argv[1],"-DX")==0) {
  796. Int i;
  797. DEBUG_LOG(("\n--- DX STACK DUMP\n"));
  798. for (i=2; i<argc; i++) {
  799. Int pc;
  800. pc = 0;
  801. sscanf(argv[i], "%x", &pc);
  802. char name[_MAX_PATH], file[_MAX_PATH];
  803. unsigned int line;
  804. unsigned int addr;
  805. GetFunctionDetails((void*)pc, name, file, &line, &addr);
  806. DEBUG_LOG(("0x%x - %s, %s, line %d address 0x%x\n", pc, name, file, line, addr));
  807. }
  808. DEBUG_LOG(("\n--- END OF DX STACK DUMP\n"));
  809. return 0;
  810. }
  811. #ifdef _DEBUG
  812. // Turn on Memory heap tracking
  813. int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
  814. tmpFlag |= (_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
  815. tmpFlag &= ~_CRTDBG_CHECK_CRT_DF;
  816. _CrtSetDbgFlag( tmpFlag );
  817. #endif
  818. // install debug callbacks
  819. // WWDebug_Install_Message_Handler(WWDebug_Message_Callback);
  820. // WWDebug_Install_Assert_Handler(WWAssert_Callback);
  821. // [SKB: Jun 24 2003 @ 1:50pm] :
  822. // Force to be loaded from a file, not a resource so same exe can be used in germany and retail.
  823. gLoadScreenBitmap = (HBITMAP)LoadImage(hInstance, "Install_Final.bmp", IMAGE_BITMAP, 0, 0, LR_SHARED|LR_LOADFROMFILE);
  824. // register windows class and create application window
  825. if( initializeAppWindows( hInstance, nCmdShow, ApplicationIsWindowed) == false )
  826. return 0;
  827. if (gLoadScreenBitmap!=NULL) {
  828. ::DeleteObject(gLoadScreenBitmap);
  829. gLoadScreenBitmap = NULL;
  830. }
  831. // BGC - initialize COM
  832. // OleInitialize(NULL);
  833. // start the log
  834. DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
  835. initMemoryManager();
  836. // Set up version info
  837. TheVersion = NEW Version;
  838. TheVersion->setVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_BUILDNUM, VERSION_LOCALBUILDNUM,
  839. AsciiString(VERSION_BUILDUSER), AsciiString(VERSION_BUILDLOC),
  840. AsciiString(__TIME__), AsciiString(__DATE__));
  841. #ifdef DO_COPY_PROTECTION
  842. if (!CopyProtect::isLauncherRunning())
  843. {
  844. DEBUG_LOG(("Launcher is not running - about to bail\n"));
  845. delete TheVersion;
  846. TheVersion = NULL;
  847. shutdownMemoryManager();
  848. DEBUG_SHUTDOWN();
  849. return 0;
  850. }
  851. #endif
  852. //Create a mutex with a unique name to Generals in order to determine if
  853. //our app is already running.
  854. //WARNING: DO NOT use this number for any other application except Generals.
  855. GeneralsMutex = CreateMutex(NULL, FALSE, GENERALS_GUID);
  856. if (GetLastError() == ERROR_ALREADY_EXISTS)
  857. {
  858. HWND ccwindow = FindWindow(GENERALS_GUID, NULL);
  859. if (ccwindow)
  860. {
  861. SetForegroundWindow(ccwindow);
  862. ShowWindow(ccwindow, SW_RESTORE);
  863. }
  864. if (GeneralsMutex != NULL)
  865. {
  866. CloseHandle(GeneralsMutex);
  867. GeneralsMutex = NULL;
  868. }
  869. DEBUG_LOG(("Generals is already running...Bail!\n"));
  870. delete TheVersion;
  871. TheVersion = NULL;
  872. shutdownMemoryManager();
  873. DEBUG_SHUTDOWN();
  874. return 0;
  875. }
  876. DEBUG_LOG(("Create GeneralsMutex okay.\n"));
  877. #ifdef DO_COPY_PROTECTION
  878. if (!CopyProtect::notifyLauncher())
  879. {
  880. DEBUG_LOG(("Could not talk to the launcher - about to bail\n"));
  881. delete TheVersion;
  882. TheVersion = NULL;
  883. shutdownMemoryManager();
  884. DEBUG_SHUTDOWN();
  885. return 0;
  886. }
  887. #endif
  888. DEBUG_LOG(("CRC message is %d\n", GameMessage::MSG_LOGIC_CRC));
  889. // run the game main loop
  890. GameMain(argc, argv);
  891. #ifdef DO_COPY_PROTECTION
  892. // Clean up copy protection
  893. CopyProtect::shutdown();
  894. #endif
  895. delete TheVersion;
  896. TheVersion = NULL;
  897. #ifdef MEMORYPOOL_DEBUG
  898. TheMemoryPoolFactory->debugMemoryReport(REPORT_POOLINFO | REPORT_POOL_OVERFLOW | REPORT_SIMPLE_LEAKS, 0, 0);
  899. #endif
  900. #if defined(_DEBUG) || defined(_INTERNAL)
  901. TheMemoryPoolFactory->memoryPoolUsageReport("AAAMemStats");
  902. #endif
  903. // close the log
  904. shutdownMemoryManager();
  905. DEBUG_SHUTDOWN();
  906. // BGC - shut down COM
  907. // OleUninitialize();
  908. }
  909. catch (...)
  910. {
  911. }
  912. TheAsciiStringCriticalSection = NULL;
  913. TheUnicodeStringCriticalSection = NULL;
  914. TheDmaCriticalSection = NULL;
  915. TheMemoryPoolCriticalSection = NULL;
  916. return 0;
  917. } // end WinMain
  918. // CreateGameEngine ===========================================================
  919. /** Create the Win32 game engine we're going to use */
  920. //=============================================================================
  921. GameEngine *CreateGameEngine( void )
  922. {
  923. Win32GameEngine *engine;
  924. engine = NEW Win32GameEngine;
  925. //game engine may not have existed when app got focus so make sure it
  926. //knows about current focus state.
  927. engine->setIsActive(isWinMainActive);
  928. return engine;
  929. } // end CreateGameEngine