winWindow.cpp

Engine/source/platformWin32/winWindow.cpp

More...

Public Defines

define
dIsStandardVK(c)                           (((0x08 <= (c)) && ((c) <= 0x12)) || \
                          ((c) == 0x1b) ||                    \
                          ((0x20 <= (c)) && ((c) <= 0x2e)) || \
                          ((0x30 <= (c)) && ((c) <= 0x39)) || \
                          ((0x41 <= (c)) && ((c) <= 0x5a)) || \
                          ((0x70 <= (c)) && ((c) <= 0x7B)))

Public Functions

DefineEngineFunction(isKoreanBuild , bool , () , "isKoreanBuild()" )
main(S32 argc, const char ** argv)
run(S32 argc, const char ** argv)
TorqueMain(S32 argc, const char ** argv)
WinMain(HINSTANCE hInstance, HINSTANCE , LPSTR lpszCmdLine, S32 )

Detailed Description

Public Defines

dIsStandardVK(c)                           (((0x08 <= (c)) && ((c) <= 0x12)) || \
                          ((c) == 0x1b) ||                    \
                          ((0x20 <= (c)) && ((c) <= 0x2e)) || \
                          ((0x30 <= (c)) && ((c) <= 0x39)) || \
                          ((0x41 <= (c)) && ((c) <= 0x5a)) || \
                          ((0x70 <= (c)) && ((c) <= 0x7B)))

Public Variables

HIMC gIMEContext 
HANDLE gMutexHandle 
bool LinkConsoleFunctions 
bool sgDoubleByteEnabled 
MRandomLCG sgPlatRandom 
bool sgQueueEvents 
const char * TorqueRegKey 
Win32PlatState winState 

Public Functions

createFontInit()

createFontShutdown()

DefineEngineFunction(isKoreanBuild , bool , () , "isKoreanBuild()" )

DIK_to_Key(U8 dikCode)

handleRedBookCallback(U32 code, U32 deviceId)

InitInput()

installRedBookDevices()

main(S32 argc, const char ** argv)

run(S32 argc, const char ** argv)

TorqueMain(S32 argc, const char ** argv)

WinMain(HINSTANCE hInstance, HINSTANCE , LPSTR lpszCmdLine, S32 )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "platformWin32/platformWin32.h"
 26#include "platformWin32/winConsole.h"
 27#include "platformWin32/winDirectInput.h"
 28#include "windowManager/win32/win32Window.h"
 29#include "console/console.h"
 30#include "console/engineAPI.h"
 31#include "math/mRandom.h"
 32#include "core/stream/fileStream.h"
 33#include "T3D/resource.h"
 34#include "gfx/gfxInit.h"
 35#include "gfx/gfxDevice.h"
 36#include "core/strings/unicode.h"
 37#include "gui/core/guiCanvas.h"
 38
 39
 40extern void createFontInit();
 41extern void createFontShutdown();
 42extern void installRedBookDevices();
 43extern void handleRedBookCallback(U32, U32);
 44
 45static MRandomLCG sgPlatRandom;
 46static bool sgQueueEvents;
 47
 48// is keyboard input a standard (non-changing) VK keycode
 49#define dIsStandardVK(c) (((0x08 <= (c)) && ((c) <= 0x12)) || \
 50                          ((c) == 0x1b) ||                    \
 51                          ((0x20 <= (c)) && ((c) <= 0x2e)) || \
 52                          ((0x30 <= (c)) && ((c) <= 0x39)) || \
 53                          ((0x41 <= (c)) && ((c) <= 0x5a)) || \
 54                          ((0x70 <= (c)) && ((c) <= 0x7B)))
 55
 56extern InputObjectInstances DIK_to_Key( U8 dikCode );
 57
 58// static helper variables
 59static HANDLE gMutexHandle = NULL;
 60static bool sgDoubleByteEnabled = false;
 61
 62// track window states
 63Win32PlatState winState;
 64
 65
 66//-----------------------------------------------------------------------------------------------------------------------------------------------------------
 67//
 68// Microsoft Layer for Unicode
 69// http://msdn.microsoft.com/library/default.asp?url=../../../library/en-us/mslu/winprog/compiling_your_application_with_the_microsoft_layer_for_unicode.asp
 70//
 71//-----------------------------------------------------------------------------------------------------------------------------------------------------------
 72#ifdef UNICODE
 73
 74HMODULE LoadUnicowsProc(void)
 75{
 76    return(LoadLibraryA("unicows.dll"));
 77}
 78
 79#ifdef _cplusplus
 80extern "C" {
 81#endif
 82extern FARPROC _PfnLoadUnicows = (FARPROC) &LoadUnicowsProc;
 83#ifdef _cplusplus
 84}
 85#endif
 86
 87#endif
 88
 89//--------------------------------------
 90Win32PlatState::Win32PlatState()
 91{
 92   log_fp      = NULL;
 93   hinstOpenGL = NULL;
 94   hinstGLU    = NULL;
 95   hinstOpenAL = NULL;
 96   appDC       = NULL;
 97   appInstance = NULL;
 98   currentTime = 0;
 99   processId   = 0;
100}
101
102//--------------------------------------
103bool Platform::excludeOtherInstances(const char *mutexName)
104{
105#ifdef UNICODE
106   UTF16 b[512];
107   convertUTF8toUTF16((UTF8 *)mutexName, b);
108   gMutexHandle = CreateMutex(NULL, true, b);
109#else
110   gMutexHandle = CreateMutex(NULL, true, mutexName);
111#endif
112   if(!gMutexHandle)
113      return false;
114
115   if(GetLastError() == ERROR_ALREADY_EXISTS)
116   {
117      CloseHandle(gMutexHandle);
118      gMutexHandle = NULL;
119      return false;
120   }
121
122   return true;
123}
124
125void Platform::restartInstance()
126{
127   STARTUPINFO si;
128   PROCESS_INFORMATION pi;
129
130   ZeroMemory( &si, sizeof(si) );
131   si.cb = sizeof(si);
132   ZeroMemory( &pi, sizeof(pi) );
133
134   TCHAR cen_buf[2048];
135   GetModuleFileName( NULL, cen_buf, 2047);
136
137   // Start the child process. 
138   if( CreateProcess( cen_buf,
139      NULL,            // Command line
140      NULL,           // Process handle not inheritable
141      NULL,           // Thread handle not inheritable
142      FALSE,          // Set handle inheritance to FALSE
143      0,              // No creation flags
144      NULL,           // Use parent's environment block
145      NULL,           // Use parent's starting directory 
146      &si,            // Pointer to STARTUPINFO structure
147      &pi )           // Pointer to PROCESS_INFORMATION structure
148      != false )
149   {
150      WaitForInputIdle( pi.hProcess, 5000 );
151      CloseHandle( pi.hProcess );
152      CloseHandle( pi.hThread );
153   }
154}
155
156///just check if the app's global mutex exists, and if so, 
157///return true - otherwise, false. Should be called before ExcludeOther 
158/// at very start of app execution.
159bool Platform::checkOtherInstances(const char *mutexName)
160{
161#ifdef TORQUE_MULTITHREAD
162
163   HANDLE pMutex  =  NULL;
164   
165#ifdef UNICODE
166   UTF16 b[512];
167   convertUTF8toUTF16((UTF8 *)mutexName, b);
168   pMutex  = CreateMutex(NULL, true, b);
169#else
170   pMutex = CreateMutex(NULL, true, mutexName);
171#endif
172
173   if(!pMutex)
174      return false;
175
176   if(GetLastError() == ERROR_ALREADY_EXISTS)
177   {
178      //another mutex of the same name exists
179      //close ours
180      CloseHandle(pMutex);
181      pMutex = NULL;
182      return true;
183   }
184
185   CloseHandle(pMutex);
186   pMutex = NULL;
187#endif
188
189   //we don;t care, always false
190   return false;
191}
192
193#ifndef TORQUE_SDL
194//--------------------------------------
195void Platform::AlertOK(const char *windowTitle, const char *message)
196{
197   ShowCursor(true);
198#ifdef UNICODE
199   UTF16 m[1024], t[512];
200   convertUTF8toUTF16((UTF8 *)windowTitle, t);
201   convertUTF8toUTF16((UTF8 *)message, m);
202   MessageBox(NULL, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OK);
203#else
204   MessageBox(NULL, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OK);
205#endif
206}
207
208//--------------------------------------
209bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
210{
211   ShowCursor(true);
212#ifdef UNICODE
213   UTF16 m[1024], t[512];
214   convertUTF8toUTF16((UTF8 *)windowTitle, t);
215   convertUTF8toUTF16((UTF8 *)message, m);
216   return MessageBox(NULL, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OKCANCEL) == IDOK;
217#else
218   return MessageBox(NULL, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OKCANCEL) == IDOK;
219#endif
220}
221
222//--------------------------------------
223bool Platform::AlertRetry(const char *windowTitle, const char *message)
224{
225   ShowCursor(true);
226#ifdef UNICODE
227   UTF16 m[1024], t[512];
228   convertUTF8toUTF16((UTF8 *)windowTitle, t);
229   convertUTF8toUTF16((UTF8 *)message, m);
230   return (MessageBox(NULL, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_RETRYCANCEL) == IDRETRY);
231#else
232   return (MessageBox(NULL, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_RETRYCANCEL) == IDRETRY);
233#endif
234}
235
236Platform::ALERT_ASSERT_RESULT Platform::AlertAssert(const char *windowTitle, const char *message)
237{
238#ifndef TORQUE_TOOLS
239   ShowCursor(true);
240#endif // TORQUE_TOOLS
241
242#ifdef UNICODE
243   UTF16 messageUTF[1024], title[512];
244   convertUTF8toUTF16((UTF8 *)windowTitle, title);
245   convertUTF8toUTF16((UTF8 *)message, messageUTF);
246#else
247   const char* messageUTF = message;
248   const char* title = windowTitle;
249#endif
250
251   // TODO: Change this to a custom dialog that has Exit, Ignore, Ignore All, and Debug buttons
252   ALERT_ASSERT_RESULT alertResult = ALERT_ASSERT_DEBUG;
253   int result = MessageBox(winState.appWindow, messageUTF, title, MB_ABORTRETRYIGNORE | MB_ICONSTOP | MB_DEFBUTTON2 | MB_TASKMODAL | MB_SETFOREGROUND);
254   switch( result )
255   {
256      case IDABORT:
257         alertResult = ALERT_ASSERT_EXIT;
258         break;
259      case IDIGNORE:
260         alertResult = ALERT_ASSERT_IGNORE;
261         break;
262      default:
263      case IDRETRY:
264         alertResult = ALERT_ASSERT_DEBUG;
265         break;
266   }
267
268   return alertResult;
269}
270
271#endif
272
273//--------------------------------------
274HIMC gIMEContext;
275
276static void InitInput()
277{
278#ifndef TORQUE_LIB
279#ifdef UNICODE
280   //gIMEContext = ImmGetContext(getWin32WindowHandle());
281   //ImmReleaseContext( getWin32WindowHandle(), gIMEContext );
282#endif
283#endif
284}
285
286//--------------------------------------
287void Platform::init()
288{
289   Con::printf("Initializing platform...");
290
291   // Set the platform variable for the scripts
292   Con::setVariable( "$platform", "windows" );
293
294   WinConsole::create();
295
296   if ( !WinConsole::isEnabled() )
297      Input::init();
298
299   InitInput();   // in case DirectInput falls through
300
301   installRedBookDevices();
302
303   sgDoubleByteEnabled = GetSystemMetrics( SM_DBCSENABLED );
304   sgQueueEvents = true;
305   Con::printf("Done");
306}
307
308//--------------------------------------
309void Platform::shutdown()
310{
311   sgQueueEvents = false;
312
313   if(gMutexHandle)
314      CloseHandle(gMutexHandle);
315
316   Input::destroy();
317   
318   GFXDevice::destroy();
319
320   WinConsole::destroy();
321}
322
323extern bool LinkConsoleFunctions;
324
325#ifndef TORQUE_SHARED
326
327extern S32 TorqueMain(S32 argc, const char **argv);
328
329//--------------------------------------
330static S32 run(S32 argc, const char **argv)
331{
332   // Console hack to ensure consolefunctions get linked in
333   LinkConsoleFunctions=true;
334
335   createFontInit();
336
337   S32 ret = TorqueMain(argc, argv);
338
339   createFontShutdown();
340
341   return ret;
342}
343
344//--------------------------------------
345S32 main(S32 argc, const char **argv)
346{
347   winState.appInstance = GetModuleHandle(NULL);
348   return run(argc, argv);
349}
350
351//--------------------------------------
352
353#include "app/mainLoop.h"
354
355S32 WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
356{
357   Vector<char*> argv( __FILE__, __LINE__ );
358
359   enum { moduleNameSize = 256 };
360   char moduleName[moduleNameSize];
361#ifdef TORQUE_UNICODE
362   {
363      TCHAR buf[ moduleNameSize ];
364      GetModuleFileNameW( NULL, buf, moduleNameSize );
365      convertUTF16toUTF8( buf, moduleName );
366   }
367#else
368   GetModuleFileNameA(NULL, moduleName, moduleNameSize);
369#endif
370   argv.push_back(moduleName);
371
372   for (const char* word,*ptr = lpszCmdLine; *ptr; )
373   {
374      // Eat white space
375      for (; dIsspace(*ptr) && *ptr; ptr++)
376         ;
377      
378      // Pick out the next word
379      for (word = ptr; !dIsspace(*ptr) && *ptr; ptr++)
380         ;
381      
382      // Add the word to the argument list.
383      if (*word) 
384      {
385         S32 len = ptr - word;
386         char *arg = (char *) dMalloc(len + 1);
387         dStrncpy(arg, word, len);
388         arg[len] = 0;
389         argv.push_back(arg);
390      }
391   }
392
393   winState.appInstance = hInstance;
394
395   S32 retVal = run(argv.size(), (const char **) argv.address());
396
397   for(U32 j = 1; j < argv.size(); j++)
398      dFree(argv[j]);
399
400   return retVal;
401}
402
403#else //TORQUE_SHARED
404
405extern "C"
406{
407   bool torque_engineinit(S32 argc, const char **argv);
408   S32  torque_enginetick();
409   S32  torque_getreturnstatus();
410   bool torque_engineshutdown();
411};
412
413S32 TorqueMain(int argc, const char **argv)
414{
415   if (!torque_engineinit(argc, argv))
416      return 1;
417
418   while(torque_enginetick())
419   {
420
421   }
422
423   torque_engineshutdown();
424
425   return torque_getreturnstatus();
426
427}
428
429
430
431extern "C" {
432
433S32 torque_winmain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
434{
435   Vector<char*> argv( __FILE__, __LINE__ );
436
437   enum { moduleNameSize = 256 };
438   char moduleName[moduleNameSize];
439#ifdef TORQUE_UNICODE
440   {
441      TCHAR buf[ moduleNameSize ];
442      GetModuleFileNameW( NULL, buf, moduleNameSize );
443      convertUTF16toUTF8( buf, moduleName );
444   }
445#else
446   GetModuleFileNameA(NULL, moduleName, moduleNameSize);
447#endif
448   argv.push_back(moduleName);
449
450   for (const char* word,*ptr = lpszCmdLine; *ptr; )
451   {
452      // Eat white space
453      for (; dIsspace(*ptr) && *ptr; ptr++)
454         ;
455
456      // Test for quotes
457      bool withinQuotes = dIsquote(*ptr);
458
459      if (!withinQuotes)
460      {
461         // Pick out the next word
462         for (word = ptr; !dIsspace(*ptr) && *ptr; ptr++)
463            ;
464      }
465      else
466      {
467         // Advance past the first quote.  We don't want to include it.
468         ptr++;
469
470         // Pick out the next quote
471         for (word = ptr; !dIsquote(*ptr) && *ptr; ptr++)
472            ;
473      }
474
475      // Add the word to the argument list.
476      if (*word) 
477      {
478         S32 len = ptr - word;
479         char *arg = (char *) dMalloc(len + 1);
480         dStrncpy(arg, word, len);
481         arg[len] = 0;
482         argv.push_back(arg);
483      }
484
485      // If we had a quote, skip past it for the next arg
486      if (withinQuotes && *ptr)
487      {
488         ptr++;
489      }
490   }
491
492   winState.appInstance = hInstance;
493
494   S32 retVal = TorqueMain(argv.size(), (const char **) argv.address());
495
496   for(U32 j = 1; j < argv.size(); j++)
497      dFree(argv[j]);
498
499   return retVal;
500}
501
502} // extern "C"
503
504#endif
505
506
507
508//--------------------------------------
509
510F32 Platform::getRandom()
511{
512   return sgPlatRandom.randF();
513}
514
515#ifndef TORQUE_SDL
516////--------------------------------------
517/// Spawn the default Operating System web browser with a URL
518/// @param webAddress URL to pass to browser
519/// @return true if browser successfully spawned
520bool Platform::openWebBrowser( const char* webAddress )
521{
522   static bool sHaveKey = false;
523   static wchar_t sWebKey[512];
524   char utf8WebKey[512];
525
526   {
527      HKEY regKey;
528      DWORD size = sizeof( sWebKey );
529
530      if ( RegOpenKeyEx( HKEY_CLASSES_ROOT, dT("\\http\\shell\\open\\command"), 0, KEY_QUERY_VALUE, &regKey ) != ERROR_SUCCESS )
531      {
532         Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to open the HKCR\\http registry key!!!");
533         return( false );
534      }
535
536      if ( RegQueryValueEx( regKey, dT(""), NULL, NULL, (U8 *)sWebKey, &size ) != ERROR_SUCCESS ) 
537      {
538         Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to query the open command registry key!!!" );
539         return( false );
540      }
541
542      RegCloseKey( regKey );
543      sHaveKey = true;
544
545      convertUTF16toUTF8(sWebKey,utf8WebKey);
546
547#ifdef UNICODE
548      char *p = dStrstr((const char *)utf8WebKey, "%1"); 
549#else
550      char *p = strstr( (const char *) sWebKey  , "%1"); 
551#endif
552      if (p) *p = 0; 
553
554   }
555
556   STARTUPINFO si;
557   dMemset( &si, 0, sizeof( si ) );
558   si.cb = sizeof( si );
559
560   char buf[1024];
561#ifdef UNICODE
562   dSprintf( buf, sizeof( buf ), "%s %s", utf8WebKey, webAddress );   
563   UTF16 b[1024];
564   convertUTF8toUTF16((UTF8 *)buf, b);
565#else
566   dSprintf( buf, sizeof( buf ), "%s %s", sWebKey, webAddress );   
567#endif
568
569   //Con::errorf( ConsoleLogEntry::General, "** Web browser command = %s **", buf );
570
571   PROCESS_INFORMATION pi;
572   dMemset( &pi, 0, sizeof( pi ) );
573   CreateProcess( NULL,
574#ifdef UNICODE
575      b,
576#else
577      buf, 
578#endif
579      NULL,
580      NULL,
581      false,
582      CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
583      NULL,
584      NULL,
585      &si,
586      &pi );
587
588   return( true );
589}
590#endif
591
592//--------------------------------------
593// Login password routines:
594//--------------------------------------
595#ifdef UNICODE
596static const UTF16* TorqueRegKey = dT("SOFTWARE\\GarageGames\\Torque");
597#else
598static const char* TorqueRegKey = "SOFTWARE\\GarageGames\\Torque";
599#endif
600
601const char* Platform::getLoginPassword()
602{
603   HKEY regKey;
604   char* returnString = NULL;
605   if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TorqueRegKey, 0, KEY_QUERY_VALUE, &regKey ) == ERROR_SUCCESS )
606   {
607      U8 buf[32];
608      DWORD size = sizeof( buf );
609      if ( RegQueryValueEx( regKey, dT("LoginPassword"), NULL, NULL, buf, &size ) == ERROR_SUCCESS )
610      {
611         returnString = Con::getReturnBuffer( size + 1 );
612         dStrcpy( returnString, (const char*) buf, size + 1 );
613      }
614
615      RegCloseKey( regKey );
616   }
617
618   if ( returnString )
619      return( returnString );
620   else
621      return( "" );
622}
623
624//--------------------------------------
625bool Platform::setLoginPassword( const char* password )
626{
627   HKEY regKey;
628   if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TorqueRegKey, 0, KEY_WRITE, &regKey ) == ERROR_SUCCESS )
629   {
630      if ( RegSetValueEx( regKey, dT("LoginPassword"), 0, REG_SZ, (const U8*) password, dStrlen( password ) + 1 ) != ERROR_SUCCESS )
631         Con::errorf( ConsoleLogEntry::General, "setLoginPassword - Failed to set the subkey value!" );
632
633      RegCloseKey( regKey );
634      return( true );
635   }
636   else
637      Con::errorf( ConsoleLogEntry::General, "setLoginPassword - Failed to open the Torque registry key!" );
638
639   return( false );
640}
641
642//--------------------------------------
643// Silly Korean registry key checker:
644//
645// NOTE: "Silly" refers to the nature of this hack, and is not intended
646//       as commentary on Koreans as a nationality. Thank you for your
647//       attention.
648//--------------------------------------
649DefineEngineFunction( isKoreanBuild, bool, ( ), , "isKoreanBuild()")
650{
651   HKEY regKey;
652   bool result = false;
653   if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TorqueRegKey, 0, KEY_QUERY_VALUE, &regKey ) == ERROR_SUCCESS )
654   {
655      DWORD val;
656      DWORD size = sizeof( val );
657      if ( RegQueryValueEx( regKey, dT("Korean"), NULL, NULL, (U8*) &val, &size ) == ERROR_SUCCESS )
658         result = ( val > 0 );
659
660      RegCloseKey( regKey );
661   }
662
663   return( result );
664}
665