win32_init.cc (18041B)
1 //======================================================================== 2 // GLFW 3.3 Win32 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 28 #include "internal.h" 29 30 #include <stdlib.h> 31 #include <malloc.h> 32 33 static const GUID _glfw_GUID_DEVINTERFACE_HID = {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}}; 34 35 #define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID 36 37 #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) 38 39 // Executables (but not DLLs) exporting this symbol with this value will be 40 // automatically directed to the high-performance GPU on Nvidia Optimus systems 41 // with up-to-date drivers 42 // 43 __declspec(dllexport) DWORD NvOptimusEnablement = 1; 44 45 // Executables (but not DLLs) exporting this symbol with this value will be 46 // automatically directed to the high-performance GPU on AMD PowerXpress systems 47 // with up-to-date drivers 48 // 49 __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; 50 51 #endif // _GLFW_USE_HYBRID_HPG 52 53 #if defined(_GLFW_BUILD_DLL) 54 55 // GLFW DLL entry point 56 // 57 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) 58 { 59 return TRUE; 60 } 61 62 #endif // _GLFW_BUILD_DLL 63 64 // Load necessary libraries (DLLs) 65 // 66 static GLFWbool loadLibraries(void) 67 { 68 _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); 69 if (!_glfw.win32.winmm.instance) 70 { 71 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to load winmm.dll"); 72 return GLFW_FALSE; 73 } 74 75 _glfw.win32.winmm.GetTime = (PFN_timeGetTime) 76 GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); 77 78 _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); 79 if (!_glfw.win32.user32.instance) 80 { 81 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to load user32.dll"); 82 return GLFW_FALSE; 83 } 84 85 _glfw.win32.user32.SetProcessDPIAware = (PFN_SetProcessDPIAware) 86 GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); 87 _glfw.win32.user32.ChangeWindowMessageFilterEx = (PFN_ChangeWindowMessageFilterEx) 88 GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); 89 90 _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); 91 if (_glfw.win32.dinput8.instance) 92 { 93 _glfw.win32.dinput8.Create = (PFN_DirectInput8Create) 94 GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); 95 } 96 97 { 98 int i; 99 const char* names[] = 100 { 101 "xinput1_4.dll", 102 "xinput1_3.dll", 103 "xinput9_1_0.dll", 104 "xinput1_2.dll", 105 "xinput1_1.dll", 106 NULL 107 }; 108 109 for (i = 0; names[i]; i++) 110 { 111 _glfw.win32.xinput.instance = LoadLibraryA(names[i]); 112 if (_glfw.win32.xinput.instance) 113 { 114 _glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities) 115 GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); 116 _glfw.win32.xinput.GetState = (PFN_XInputGetState) 117 GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); 118 119 break; 120 } 121 } 122 } 123 124 _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); 125 if (_glfw.win32.dwmapi.instance) 126 { 127 _glfw.win32.dwmapi.DwmIsCompositionEnabled = (PFN_DwmIsCompositionEnabled) 128 GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); 129 _glfw.win32.dwmapi.DwmFlush = (PFN_DwmFlush) 130 GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); 131 } 132 133 _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); 134 if (_glfw.win32.shcore.instance) 135 { 136 _glfw.win32.shcore.SetProcessDpiAwareness = (PFN_SetProcessDpiAwareness) 137 GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); 138 } 139 140 return GLFW_TRUE; 141 } 142 143 // Unload used libraries (DLLs) 144 // 145 static void freeLibraries(void) 146 { 147 if (_glfw.win32.xinput.instance) 148 FreeLibrary(_glfw.win32.xinput.instance); 149 150 if (_glfw.win32.dinput8.instance) 151 FreeLibrary(_glfw.win32.dinput8.instance); 152 153 if (_glfw.win32.winmm.instance) 154 FreeLibrary(_glfw.win32.winmm.instance); 155 156 if (_glfw.win32.user32.instance) 157 FreeLibrary(_glfw.win32.user32.instance); 158 159 if (_glfw.win32.dwmapi.instance) 160 FreeLibrary(_glfw.win32.dwmapi.instance); 161 162 if (_glfw.win32.shcore.instance) 163 FreeLibrary(_glfw.win32.shcore.instance); 164 } 165 166 // Create key code translation tables 167 // 168 static void createKeyTables(void) 169 { 170 int scancode; 171 172 memset(_glfw.win32.keycodes, -1, sizeof(_glfw.win32.keycodes)); 173 memset(_glfw.win32.scancodes, -1, sizeof(_glfw.win32.scancodes)); 174 175 _glfw.win32.keycodes[0x00B] = GLFW_KEY_0; 176 _glfw.win32.keycodes[0x002] = GLFW_KEY_1; 177 _glfw.win32.keycodes[0x003] = GLFW_KEY_2; 178 _glfw.win32.keycodes[0x004] = GLFW_KEY_3; 179 _glfw.win32.keycodes[0x005] = GLFW_KEY_4; 180 _glfw.win32.keycodes[0x006] = GLFW_KEY_5; 181 _glfw.win32.keycodes[0x007] = GLFW_KEY_6; 182 _glfw.win32.keycodes[0x008] = GLFW_KEY_7; 183 _glfw.win32.keycodes[0x009] = GLFW_KEY_8; 184 _glfw.win32.keycodes[0x00A] = GLFW_KEY_9; 185 _glfw.win32.keycodes[0x01E] = GLFW_KEY_A; 186 _glfw.win32.keycodes[0x030] = GLFW_KEY_B; 187 _glfw.win32.keycodes[0x02E] = GLFW_KEY_C; 188 _glfw.win32.keycodes[0x020] = GLFW_KEY_D; 189 _glfw.win32.keycodes[0x012] = GLFW_KEY_E; 190 _glfw.win32.keycodes[0x021] = GLFW_KEY_F; 191 _glfw.win32.keycodes[0x022] = GLFW_KEY_G; 192 _glfw.win32.keycodes[0x023] = GLFW_KEY_H; 193 _glfw.win32.keycodes[0x017] = GLFW_KEY_I; 194 _glfw.win32.keycodes[0x024] = GLFW_KEY_J; 195 _glfw.win32.keycodes[0x025] = GLFW_KEY_K; 196 _glfw.win32.keycodes[0x026] = GLFW_KEY_L; 197 _glfw.win32.keycodes[0x032] = GLFW_KEY_M; 198 _glfw.win32.keycodes[0x031] = GLFW_KEY_N; 199 _glfw.win32.keycodes[0x018] = GLFW_KEY_O; 200 _glfw.win32.keycodes[0x019] = GLFW_KEY_P; 201 _glfw.win32.keycodes[0x010] = GLFW_KEY_Q; 202 _glfw.win32.keycodes[0x013] = GLFW_KEY_R; 203 _glfw.win32.keycodes[0x01F] = GLFW_KEY_S; 204 _glfw.win32.keycodes[0x014] = GLFW_KEY_T; 205 _glfw.win32.keycodes[0x016] = GLFW_KEY_U; 206 _glfw.win32.keycodes[0x02F] = GLFW_KEY_V; 207 _glfw.win32.keycodes[0x011] = GLFW_KEY_W; 208 _glfw.win32.keycodes[0x02D] = GLFW_KEY_X; 209 _glfw.win32.keycodes[0x015] = GLFW_KEY_Y; 210 _glfw.win32.keycodes[0x02C] = GLFW_KEY_Z; 211 212 _glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE; 213 _glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH; 214 _glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA; 215 _glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL; 216 _glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT; 217 _glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET; 218 _glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS; 219 _glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD; 220 _glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET; 221 _glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON; 222 _glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH; 223 _glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2; 224 225 _glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE; 226 _glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE; 227 _glfw.win32.keycodes[0x14F] = GLFW_KEY_END; 228 _glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER; 229 _glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE; 230 _glfw.win32.keycodes[0x147] = GLFW_KEY_HOME; 231 _glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT; 232 _glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU; 233 _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; 234 _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; 235 _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE; 236 _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE; 237 _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; 238 _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; 239 _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK; 240 _glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK; 241 _glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK; 242 _glfw.win32.keycodes[0x03B] = GLFW_KEY_F1; 243 _glfw.win32.keycodes[0x03C] = GLFW_KEY_F2; 244 _glfw.win32.keycodes[0x03D] = GLFW_KEY_F3; 245 _glfw.win32.keycodes[0x03E] = GLFW_KEY_F4; 246 _glfw.win32.keycodes[0x03F] = GLFW_KEY_F5; 247 _glfw.win32.keycodes[0x040] = GLFW_KEY_F6; 248 _glfw.win32.keycodes[0x041] = GLFW_KEY_F7; 249 _glfw.win32.keycodes[0x042] = GLFW_KEY_F8; 250 _glfw.win32.keycodes[0x043] = GLFW_KEY_F9; 251 _glfw.win32.keycodes[0x044] = GLFW_KEY_F10; 252 _glfw.win32.keycodes[0x057] = GLFW_KEY_F11; 253 _glfw.win32.keycodes[0x058] = GLFW_KEY_F12; 254 _glfw.win32.keycodes[0x064] = GLFW_KEY_F13; 255 _glfw.win32.keycodes[0x065] = GLFW_KEY_F14; 256 _glfw.win32.keycodes[0x066] = GLFW_KEY_F15; 257 _glfw.win32.keycodes[0x067] = GLFW_KEY_F16; 258 _glfw.win32.keycodes[0x068] = GLFW_KEY_F17; 259 _glfw.win32.keycodes[0x069] = GLFW_KEY_F18; 260 _glfw.win32.keycodes[0x06A] = GLFW_KEY_F19; 261 _glfw.win32.keycodes[0x06B] = GLFW_KEY_F20; 262 _glfw.win32.keycodes[0x06C] = GLFW_KEY_F21; 263 _glfw.win32.keycodes[0x06D] = GLFW_KEY_F22; 264 _glfw.win32.keycodes[0x06E] = GLFW_KEY_F23; 265 _glfw.win32.keycodes[0x076] = GLFW_KEY_F24; 266 _glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT; 267 _glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL; 268 _glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT; 269 _glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER; 270 _glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN; 271 _glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT; 272 _glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL; 273 _glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT; 274 _glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER; 275 _glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN; 276 _glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT; 277 _glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT; 278 _glfw.win32.keycodes[0x148] = GLFW_KEY_UP; 279 280 _glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0; 281 _glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1; 282 _glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2; 283 _glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3; 284 _glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4; 285 _glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5; 286 _glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6; 287 _glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7; 288 _glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8; 289 _glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9; 290 _glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD; 291 _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL; 292 _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE; 293 _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER; 294 _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY; 295 _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT; 296 297 for (scancode = 0; scancode < 512; scancode++) 298 { 299 if (_glfw.win32.keycodes[scancode] > 0) 300 _glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode; 301 } 302 } 303 304 // Creates a dummy window for behind-the-scenes work 305 // 306 static HWND createHelperWindow(void) 307 { 308 MSG msg; 309 HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, 310 _GLFW_WNDCLASSNAME, 311 L"GLFW message window", 312 WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 313 0, 0, 1, 1, 314 NULL, NULL, 315 GetModuleHandleW(NULL), 316 NULL); 317 if (!window) 318 { 319 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 320 "Win32: Failed to create helper window"); 321 return NULL; 322 } 323 324 // HACK: The first call to ShowWindow is ignored if the parent process 325 // passed along a STARTUPINFO, so clear that flag with a no-op call 326 ShowWindow(window, SW_HIDE); 327 328 // Register for HID device notifications 329 { 330 DEV_BROADCAST_DEVICEINTERFACE_W dbi; 331 ZeroMemory(&dbi, sizeof(dbi)); 332 dbi.dbcc_size = sizeof(dbi); 333 dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 334 dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; 335 336 RegisterDeviceNotificationW(window, 337 (DEV_BROADCAST_HDR*) &dbi, 338 DEVICE_NOTIFY_WINDOW_HANDLE); 339 } 340 341 while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE)) 342 { 343 TranslateMessage(&msg); 344 DispatchMessageW(&msg); 345 } 346 347 return window; 348 } 349 350 351 ////////////////////////////////////////////////////////////////////////// 352 ////// GLFW internal API ////// 353 ////////////////////////////////////////////////////////////////////////// 354 355 // Returns a wide string version of the specified UTF-8 string 356 // 357 WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) 358 { 359 WCHAR* target; 360 int length; 361 362 length = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); 363 if (!length) 364 { 365 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 366 "Win32: Failed to convert string from UTF-8"); 367 return NULL; 368 } 369 370 target = calloc(length, sizeof(WCHAR)); 371 372 if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length)) 373 { 374 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 375 "Win32: Failed to convert string from UTF-8"); 376 free(target); 377 return NULL; 378 } 379 380 return target; 381 } 382 383 // Returns a UTF-8 string version of the specified wide string 384 // 385 char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) 386 { 387 char* target; 388 int length; 389 390 length = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); 391 if (!length) 392 { 393 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 394 "Win32: Failed to convert string to UTF-8"); 395 return NULL; 396 } 397 398 target = calloc(length, 1); 399 400 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL)) 401 { 402 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 403 "Win32: Failed to convert string to UTF-8"); 404 free(target); 405 return NULL; 406 } 407 408 return target; 409 } 410 411 // Reports the specified error, appending information about the last Win32 error 412 // 413 void _glfwInputErrorWin32(int error, const char* description) 414 { 415 WCHAR buffer[_GLFW_MESSAGE_SIZE] = L""; 416 char message[_GLFW_MESSAGE_SIZE] = ""; 417 418 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | 419 FORMAT_MESSAGE_IGNORE_INSERTS | 420 FORMAT_MESSAGE_MAX_WIDTH_MASK, 421 NULL, 422 GetLastError() & 0xffff, 423 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 424 buffer, 425 sizeof(buffer), 426 NULL); 427 WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL); 428 429 _glfwInputError(error, "%s: %s", description, message); 430 } 431 432 433 ////////////////////////////////////////////////////////////////////////// 434 ////// GLFW platform API ////// 435 ////////////////////////////////////////////////////////////////////////// 436 437 int _glfwPlatformInit(void) 438 { 439 // To make SetForegroundWindow work as we want, we need to fiddle 440 // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early 441 // as possible in the hope of still being the foreground process) 442 SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, 443 &_glfw.win32.foregroundLockTimeout, 0); 444 SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), 445 SPIF_SENDCHANGE); 446 447 if (!loadLibraries()) 448 return GLFW_FALSE; 449 450 createKeyTables(); 451 452 if (_glfw_SetProcessDpiAwareness) 453 _glfw_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); 454 else if (_glfw_SetProcessDPIAware) 455 _glfw_SetProcessDPIAware(); 456 457 if (!_glfwRegisterWindowClassWin32()) 458 return GLFW_FALSE; 459 460 _glfw.win32.helperWindowHandle = createHelperWindow(); 461 if (!_glfw.win32.helperWindowHandle) 462 return GLFW_FALSE; 463 464 _glfwInitTimerWin32(); 465 _glfwInitJoysticksWin32(); 466 467 _glfwPollMonitorsWin32(); 468 return GLFW_TRUE; 469 } 470 471 void _glfwPlatformTerminate(void) 472 { 473 if (_glfw.win32.helperWindowHandle) 474 DestroyWindow(_glfw.win32.helperWindowHandle); 475 476 _glfwUnregisterWindowClassWin32(); 477 478 // Restore previous foreground lock timeout system setting 479 SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 480 UIntToPtr(_glfw.win32.foregroundLockTimeout), 481 SPIF_SENDCHANGE); 482 483 free(_glfw.win32.clipboardString); 484 free(_glfw.win32.rawInput); 485 486 _glfwTerminateWGL(); 487 _glfwTerminateEGL(); 488 489 _glfwTerminateJoysticksWin32(); 490 491 freeLibraries(); 492 } 493 494 const char* _glfwPlatformGetVersionString(void) 495 { 496 return _GLFW_VERSION_NUMBER " Win32 WGL EGL" 497 #if defined(__MINGW32__) 498 " MinGW" 499 #elif defined(_MSC_VER) 500 " VisualC" 501 #endif 502 #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG) 503 " hybrid-GPU" 504 #endif 505 #if defined(_GLFW_BUILD_DLL) 506 " DLL" 507 #endif 508 ; 509 } 510