winWindow.cpp
Engine/source/platformWin32/winWindow.cpp
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 Variables
Public Functions
DefineEngineFunction(isKoreanBuild , bool , () , "isKoreanBuild()" )
DIK_to_Key(U8 dikCode)
handleRedBookCallback(U32 code, U32 deviceId)
TorqueMain(S32 argc, const char ** argv)
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, ®Key ) != 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, ®Key ) == 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, ®Key ) == 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, ®Key ) == 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