Changeset 106411 in vbox for trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
- Timestamp:
- Oct 17, 2024 7:44:43 AM (4 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
r106246 r106411 53 53 #include <iprt/asm.h> 54 54 #include <iprt/buildconfig.h> 55 #include <iprt/file.h> 55 56 #include <iprt/getopt.h> 56 57 #include <iprt/ldr.h> … … 58 59 #include <iprt/path.h> 59 60 #include <iprt/process.h> 61 #include <iprt/stream.h> 60 62 #include <iprt/system.h> 61 63 #include <iprt/time.h> … … 80 82 * Global Variables * 81 83 *********************************************************************************************************************************/ 82 int g_cVerbosity = 0; 84 /** Mutex for checking if VBoxTray already is running. */ 85 HANDLE g_hMutexAppRunning = NULL; 86 /** Whether VBoxTray is connected to a (parent) console. */ 87 bool g_fHasConsole = false; 88 /** The current verbosity level. */ 89 unsigned g_cVerbosity = 0; 83 90 HANDLE g_hStopSem; 84 91 HANDLE g_hSeamlessWtNotifyEvent = 0; … … 90 97 uint32_t g_fGuestDisplaysChanged = 0; 91 98 92 static PRTLOGGER g_pLoggerRelease = NULL; /**< This is actually the debug logger in DEBUG builds! */ 93 static uint32_t g_cHistory = 10; /**< Enable log rotation, 10 files. */ 94 static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /**< Max 1 day per file. */ 95 static uint64_t g_uHistoryFileSize = 100 * _1M; /**< Max 100MB per file. */ 96 97 #ifdef DEBUG_andy 98 static VBOXSERVICEINFO g_aServices[] = 99 { 100 { &g_SvcDescClipboard, NIL_RTTHREAD, NULL, false, false, false, false, true } 101 }; 102 #else 99 103 100 /** 104 101 * The details of the services that has been compiled in. 105 102 */ 106 static VBOX SERVICEINFO g_aServices[] =103 static VBOXTRAYSVCINFO g_aServices[] = 107 104 { 108 105 { &g_SvcDescDisplay, NIL_RTTHREAD, NULL, false, false, false, false, true }, … … 118 115 #endif 119 116 }; 120 #endif 121 122 /* The global message table. */ 123 static VBOXGLOBALMESSAGE g_vboxGlobalMessageTable[] = 117 118 /** 119 * The global message table. 120 */ 121 static VBOXTRAYGLOBALMSG g_vboxGlobalMessageTable[] = 124 122 { 125 123 /* Windows specific stuff. */ … … 131 129 /* VBoxTray specific stuff. */ 132 130 /** @todo Add new messages here! */ 133 134 131 { 135 132 NULL … … 141 138 * get (re-)created. Nice to install our tray icon. 142 139 * 143 * @return IPRTstatus code.140 * @return VBox status code. 144 141 * @param wParam 145 142 * @param lParam … … 151 148 } 152 149 150 /** 151 * Creates VBoxTray's tray icon. 152 * 153 * @returns VBox status code. 154 */ 153 155 static int vboxTrayCreateTrayIcon(void) 154 156 { … … 156 158 if (hIcon == NULL) 157 159 { 158 DWORD dwErr = GetLastError();159 LogFunc(("Could not load tray icon, error %08X\n", dwErr));160 DWORD const dwErr = GetLastError(); 161 VBoxTrayError("Could not load tray icon (%#x)\n", dwErr); 160 162 return RTErrConvertFromWin32(dwErr); 161 163 } … … 176 178 if (!Shell_NotifyIcon(NIM_ADD, &g_NotifyIconData)) 177 179 { 178 DWORD dwErr = GetLastError();179 LogFunc(("Could not create tray icon, error=%ld\n", dwErr));180 DWORD const dwErr = GetLastError(); 181 VBoxTrayError("Could not create tray icon (%#x)\n", dwErr); 180 182 rc = RTErrConvertFromWin32(dwErr); 181 183 RT_ZERO(g_NotifyIconData); … … 187 189 } 188 190 191 /** 192 * Removes VBoxTray's tray icon. 193 * 194 * @returns VBox status code. 195 */ 189 196 static void vboxTrayRemoveTrayIcon(void) 190 197 { … … 213 220 static DECLCALLBACK(int) vboxTrayServiceThread(RTTHREAD ThreadSelf, void *pvUser) 214 221 { 215 PVBOX SERVICEINFO pSvc = (PVBOXSERVICEINFO)pvUser;222 PVBOXTRAYSVCINFO pSvc = (PVBOXTRAYSVCINFO)pvUser; 216 223 AssertPtr(pSvc); 217 224 … … 229 236 RTThreadUserSignal(ThreadSelf); 230 237 231 LogFunc(("Worker for '%s' ended with %Rrc\n", pSvc->pDesc->pszName, rc));238 VBoxTrayVerbose(1, "Thread for '%s' ended with %Rrc\n", pSvc->pDesc->pszName, rc); 232 239 return rc; 233 240 } 234 241 235 static int vboxTrayServicesStart(PVBOXSERVICEENV pEnv) 242 /** 243 * Lazily calls the pfnPreInit method on each service. 244 * 245 * @returns VBox status code, error message displayed. 246 */ 247 static int vboxTrayServicesLazyPreInit(void) 248 { 249 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) 250 if (!g_aServices[j].fPreInited) 251 { 252 int rc = g_aServices[j].pDesc->pfnPreInit(); 253 if (RT_FAILURE(rc)) 254 return VBoxTrayError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName, rc); 255 g_aServices[j].fPreInited = true; 256 } 257 return VINF_SUCCESS; 258 } 259 260 /** 261 * Starts all services. 262 * 263 * @returns VBox status code. 264 * @param pEnv Service environment to use. 265 */ 266 static int vboxTrayServicesStart(PVBOXTRAYSVCENV pEnv) 236 267 { 237 268 AssertPtrReturn(pEnv, VERR_INVALID_POINTER); 238 269 239 LogRel(("Starting services ...\n"));270 VBoxTrayInfo("Starting services ...\n"); 240 271 241 272 int rc = VINF_SUCCESS; 242 273 274 size_t cServicesStarted = 0; 275 243 276 for (unsigned i = 0; i < RT_ELEMENTS(g_aServices); i++) 244 277 { 245 PVBOXSERVICEINFO pSvc = &g_aServices[i]; 246 LogRel(("Starting service '%s' ...\n", pSvc->pDesc->pszName)); 278 PVBOXTRAYSVCINFO pSvc = &g_aServices[i]; 279 280 if (!pSvc->fEnabled) 281 { 282 VBoxTrayInfo("Skipping starting service '%s' (disabled)\n", pSvc->pDesc->pszName); 283 continue; 284 } 285 286 VBoxTrayInfo("Starting service '%s' ...\n", pSvc->pDesc->pszName); 247 287 248 288 pSvc->hThread = NIL_RTTHREAD; … … 261 301 { 262 302 case VERR_NOT_SUPPORTED: 263 LogRel(("Service '%s' is not supported on this system\n", pSvc->pDesc->pszName));303 VBoxTrayInfo("Service '%s' is not supported on this system\n", pSvc->pDesc->pszName); 264 304 rc2 = VINF_SUCCESS; /* Keep going. */ 265 305 break; 266 306 267 307 case VERR_HGCM_SERVICE_NOT_FOUND: 268 LogRel(("Service '%s' is not available on the host\n", pSvc->pDesc->pszName));308 VBoxTrayInfo("Service '%s' is not available on the host\n", pSvc->pDesc->pszName); 269 309 rc2 = VINF_SUCCESS; /* Keep going. */ 270 310 break; 271 311 272 312 default: 273 LogRel(("Failed to initialize service '%s', rc=%Rrc\n", pSvc->pDesc->pszName, rc2));313 VBoxTrayError("Failed to initialize service '%s', rc=%Rrc\n", pSvc->pDesc->pszName, rc2); 274 314 break; 275 315 } … … 288 328 if (pSvc->fShutdown) 289 329 { 290 LogRel(("Service '%s' failed to start!\n", pSvc->pDesc->pszName));330 VBoxTrayError("Service '%s' failed to start!\n", pSvc->pDesc->pszName); 291 331 rc = VERR_GENERAL_FAILURE; 292 332 } 293 333 else 294 LogRel(("Service '%s' started\n", pSvc->pDesc->pszName)); 334 { 335 cServicesStarted++; 336 VBoxTrayInfo("Service '%s' started\n", pSvc->pDesc->pszName); 337 } 295 338 } 296 339 else 297 340 { 298 LogRel(("Failed to start thread for service '%s': %Rrc\n", rc2));341 VBoxTrayInfo("Failed to start thread for service '%s': %Rrc\n", rc2); 299 342 if (pSvc->pDesc->pfnDestroy) 300 343 pSvc->pDesc->pfnDestroy(pSvc->pInstance); … … 307 350 } 308 351 309 if (RT_SUCCESS(rc)) 310 LogRel(("All services started\n")); 311 else 312 LogRel(("Services started, but some with errors\n")); 352 VBoxTrayInfo("%zu/%zu service(s) started\n", cServicesStarted, RT_ELEMENTS(g_aServices)); 353 if (RT_FAILURE(rc)) 354 VBoxTrayInfo("Some service(s) reported errors when starting -- see log above\n"); 313 355 314 356 LogFlowFuncLeaveRC(rc); … … 316 358 } 317 359 318 static int vboxTrayServicesStop(VBOXSERVICEENV *pEnv) 360 /** 361 * Stops all services. 362 * 363 * @returns VBox status code. 364 * @param pEnv Service environment to use. 365 */ 366 static int vboxTrayServicesStop(VBOXTRAYSVCENV *pEnv) 319 367 { 320 368 AssertPtrReturn(pEnv, VERR_INVALID_POINTER); 321 369 322 LogRel2(("Stopping all services ...\n"));370 VBoxTrayVerbose(1, "Stopping all services ...\n"); 323 371 324 372 /* … … 333 381 for (unsigned i = 0; i < RT_ELEMENTS(g_aServices); i++) 334 382 { 335 PVBOX SERVICEINFO pSvc = &g_aServices[i];383 PVBOXTRAYSVCINFO pSvc = &g_aServices[i]; 336 384 if ( pSvc->fStarted 337 385 && pSvc->pDesc->pfnStop) 338 386 { 339 LogRel2(("Calling stop function for service '%s' ...\n", pSvc->pDesc->pszName));387 VBoxTrayVerbose(1, "Calling stop function for service '%s' ...\n", pSvc->pDesc->pszName); 340 388 int rc2 = pSvc->pDesc->pfnStop(pSvc->pInstance); 341 389 if (RT_FAILURE(rc2)) 342 LogRel(("Failed to stop service '%s': %Rrc\n", pSvc->pDesc->pszName, rc2));343 } 344 } 345 346 LogRel2(("All stop functions for services called\n"));390 VBoxTrayError("Failed to stop service '%s': %Rrc\n", pSvc->pDesc->pszName, rc2); 391 } 392 } 393 394 VBoxTrayVerbose(2, "All stop functions for services called\n"); 347 395 348 396 int rc = VINF_SUCCESS; … … 353 401 for (unsigned i = 0; i < RT_ELEMENTS(g_aServices); i++) 354 402 { 355 PVBOX SERVICEINFO pSvc = &g_aServices[i];403 PVBOXTRAYSVCINFO pSvc = &g_aServices[i]; 356 404 if (!pSvc->fEnabled) /* Only stop services which were started before. */ 357 405 continue; … … 359 407 if (pSvc->hThread != NIL_RTTHREAD) 360 408 { 361 LogRel2(("Waiting for service '%s' to stop ...\n", pSvc->pDesc->pszName));409 VBoxTrayVerbose(1, "Waiting for service '%s' to stop ...\n", pSvc->pDesc->pszName); 362 410 int rc2 = VINF_SUCCESS; 363 411 for (int j = 0; j < 30; j++) /* Wait 30 seconds in total */ … … 369 417 if (RT_FAILURE(rc2)) 370 418 { 371 LogRel(("Service '%s' failed to stop (%Rrc)\n", pSvc->pDesc->pszName, rc2));419 VBoxTrayError("Service '%s' failed to stop (%Rrc)\n", pSvc->pDesc->pszName, rc2); 372 420 if (RT_SUCCESS(rc)) 373 421 rc = rc2; … … 378 426 && pSvc->pInstance) /* pInstance might be NULL if initialization of a service failed. */ 379 427 { 380 LogRel2(("Terminating service '%s' ...\n", pSvc->pDesc->pszName));428 VBoxTrayVerbose(1, "Terminating service '%s' ...\n", pSvc->pDesc->pszName); 381 429 pSvc->pDesc->pfnDestroy(pSvc->pInstance); 382 430 } … … 384 432 385 433 if (RT_SUCCESS(rc)) 386 LogRel(("All services stopped\n"));434 VBoxTrayVerbose(1, "All services stopped\n"); 387 435 388 436 LogFlowFuncLeaveRC(rc); … … 390 438 } 391 439 392 static int vboxTrayRegisterGlobalMessages(PVBOXGLOBALMESSAGE pTable) 440 /** 441 * Registers all global window messages of a specific table. 442 * 443 * @returns VBox status code. 444 * @param pTable Table to register messages for. 445 */ 446 static int vboxTrayRegisterGlobalMessages(PVBOXTRAYGLOBALMSG pTable) 393 447 { 394 448 int rc = VINF_SUCCESS; … … 403 457 { 404 458 DWORD dwErr = GetLastError(); 405 Log(("Registering global message \"%s\" failed, error = %08X\n", dwErr));459 VBoxTrayError("Registering global message \"%s\" failed, error = %08X\n", pTable->pszName, dwErr); 406 460 rc = RTErrConvertFromWin32(dwErr); 407 461 } … … 413 467 } 414 468 415 static bool vboxTrayHandleGlobalMessages(PVBOXGLOBALMESSAGE pTable, UINT uMsg, 469 /** 470 * Handler for global (registered) window messages. 471 * 472 * @returns \c true if message got handeled, \c false if not. 473 * @param pTable Message table to look message up in. 474 * @param uMsg Message ID to handle. 475 * @param wParam WPARAM of the message. 476 * @param lParam LPARAM of the message. 477 */ 478 static bool vboxTrayHandleGlobalMessages(PVBOXTRAYGLOBALMSG pTable, UINT uMsg, 416 479 WPARAM wParam, LPARAM lParam) 417 480 { … … 434 497 435 498 /** 436 * Header/footer callback for the release logger. 437 * 438 * @param pLoggerRelease 439 * @param enmPhase 440 * @param pfnLog 441 */ 442 static DECLCALLBACK(void) vboxTrayLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog) 443 { 444 /* Some introductory information. */ 445 static RTTIMESPEC s_TimeSpec; 446 char szTmp[256]; 447 if (enmPhase == RTLOGPHASE_BEGIN) 448 RTTimeNow(&s_TimeSpec); 449 RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp)); 450 451 switch (enmPhase) 452 { 453 case RTLOGPHASE_BEGIN: 454 { 455 pfnLog(pLoggerRelease, 456 "VBoxTray %s r%s %s (%s %s) release log\n" 457 "Log opened %s\n", 458 RTBldCfgVersion(), RTBldCfgRevisionStr(), VBOX_BUILD_TARGET, 459 __DATE__, __TIME__, szTmp); 460 461 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp)); 462 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) 463 pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp); 464 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp)); 465 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) 466 pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp); 467 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp)); 468 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) 469 pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp); 470 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) 471 pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp); 472 473 /* the package type is interesting for Linux distributions */ 474 char szExecName[RTPATH_MAX]; 475 char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName)); 476 pfnLog(pLoggerRelease, 477 "Executable: %s\n" 478 "Process ID: %u\n" 479 "Package type: %s" 480 #ifdef VBOX_OSE 481 " (OSE)" 482 #endif 483 "\n", 484 pszExecName ? pszExecName : "unknown", 485 RTProcSelf(), 486 VBOX_PACKAGE_STRING); 487 break; 488 } 489 490 case RTLOGPHASE_PREROTATE: 491 pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp); 492 break; 493 494 case RTLOGPHASE_POSTROTATE: 495 pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp); 496 break; 497 498 case RTLOGPHASE_END: 499 pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp); 500 break; 501 502 default: 503 /* nothing */; 504 } 505 } 506 507 /** 508 * Creates the default release logger outputting to the specified file. 509 * 510 * @return IPRT status code. 511 * @param pszLogFile Path to log file to use. Can be NULL if not needed. 512 */ 513 static int vboxTrayLogCreate(const char *pszLogFile) 514 { 515 /* Create release (or debug) logger (stdout + file). */ 516 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; 517 #ifdef DEBUG 518 static const char s_szEnvVarPfx[] = "VBOXTRAY_LOG"; 519 static const char s_szGroupSettings[] = "all.e.l.f"; 520 #else 521 static const char s_szEnvVarPfx[] = "VBOXTRAY_RELEASE_LOG"; 522 static const char s_szGroupSettings[] = "all"; 523 #endif 524 RTERRINFOSTATIC ErrInfo; 525 int rc = RTLogCreateEx(&g_pLoggerRelease, s_szEnvVarPfx, 526 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_USECRLF, 527 s_szGroupSettings, RT_ELEMENTS(s_apszGroups), s_apszGroups, UINT32_MAX, 528 0 /*cBufDescs*/, NULL /*paBufDescs*/, RTLOGDEST_STDOUT, 529 vboxTrayLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime, 530 NULL /*pOutputIf*/, NULL /*pvOutputIfUser*/, 531 RTErrInfoInitStatic(&ErrInfo), "%s", pszLogFile ? pszLogFile : ""); 532 if (RT_SUCCESS(rc)) 533 { 534 #ifdef DEBUG 535 /* Register this logger as the _debug_ logger. */ 536 RTLogSetDefaultInstance(g_pLoggerRelease); 537 #else 538 /* Register this logger as the release logger. */ 539 RTLogRelSetDefaultInstance(g_pLoggerRelease); 540 #endif 541 /* If verbosity is explicitly set, make sure to increase the logging levels for 542 * the logging groups we offer functionality for in VBoxTray. */ 543 if (g_cVerbosity) 544 { 545 /* All groups we want to enable logging for VBoxTray. */ 546 #ifdef DEBUG 547 const char *apszGroups[] = { "guest_dnd", "shared_clipboard" }; 548 #else /* For release builds we always want all groups being logged in verbose mode. Don't change this! */ 549 const char *apszGroups[] = { "all" }; 550 #endif 551 char szGroupSettings[_1K]; 552 553 szGroupSettings[0] = '\0'; 554 555 for (size_t i = 0; i < RT_ELEMENTS(apszGroups); i++) 556 { 557 if (i > 0) 558 rc = RTStrCat(szGroupSettings, sizeof(szGroupSettings), "+"); 559 if (RT_SUCCESS(rc)) 560 rc = RTStrCat(szGroupSettings, sizeof(szGroupSettings), apszGroups[i]); 561 if (RT_FAILURE(rc)) 562 break; 563 564 switch (g_cVerbosity) 565 { 566 case 1: 567 rc = RTStrCat(szGroupSettings, sizeof(szGroupSettings), ".e.l.l2"); 568 break; 569 570 case 2: 571 rc = RTStrCat(szGroupSettings, sizeof(szGroupSettings), ".e.l.l2.l3"); 572 break; 573 574 case 3: 575 rc = RTStrCat(szGroupSettings, sizeof(szGroupSettings), ".e.l.l2.l3.l4"); 576 break; 577 578 case 4: 579 RT_FALL_THROUGH(); 580 default: 581 rc = RTStrCat(szGroupSettings, sizeof(szGroupSettings), ".e.l.l2.l3.l4.f"); 582 break; 583 } 584 585 if (RT_FAILURE(rc)) 586 break; 587 } 588 589 LogRel(("Verbose log settings are: %s\n", szGroupSettings)); 590 591 if (RT_SUCCESS(rc)) 592 rc = RTLogGroupSettings(g_pLoggerRelease, szGroupSettings); 593 if (RT_FAILURE(rc)) 594 RTMsgError("Setting log group settings failed, rc=%Rrc\n", rc); 595 } 596 597 /* Explicitly flush the log in case of VBOXTRAY_RELEASE_LOG=buffered. */ 598 RTLogFlush(g_pLoggerRelease); 599 } 600 else 601 VBoxTrayShowError(ErrInfo.szMsg); 602 603 return rc; 604 } 605 606 static void vboxTrayLogDestroy(void) 607 { 608 /* Only want to destroy the release logger before calling exit(). The debug 609 logger can be useful after that point... */ 610 RTLogDestroy(RTLogRelSetDefaultInstance(NULL)); 611 } 612 613 /** 614 * Displays an error message. 615 * 616 * @returns RTEXITCODE_FAILURE. 617 * @param pszFormat The message text. 618 * @param ... Format arguments. 619 */ 620 RTEXITCODE VBoxTrayShowError(const char *pszFormat, ...) 621 { 622 va_list args; 623 va_start(args, pszFormat); 624 char *psz = NULL; 625 RTStrAPrintfV(&psz, pszFormat, args); 626 va_end(args); 627 628 AssertPtr(psz); 629 LogRel(("Error: %s", psz)); 630 631 MessageBox(GetDesktopWindow(), psz, "VBoxTray - Error", MB_OK | MB_ICONERROR); 632 633 RTStrFree(psz); 634 635 return RTEXITCODE_FAILURE; 636 } 637 499 * Destroys the invisible tool window of VBoxTray. 500 */ 638 501 static void vboxTrayDestroyToolWindow(void) 639 502 { 640 503 if (g_hwndToolWindow) 641 504 { 642 Log(("Destroying tool window ...\n"));643 644 505 /* Destroy the tool window. */ 645 506 DestroyWindow(g_hwndToolWindow); … … 650 511 } 651 512 513 /** 514 * Creates the invisible tool window of VBoxTray. 515 * 516 * @returns VBox status code. 517 */ 652 518 static int vboxTrayCreateToolWindow(void) 653 519 { … … 666 532 { 667 533 dwErr = GetLastError(); 668 Log(("Registering invisible tool window failed, error = %08X\n", dwErr));534 VBoxTrayError("Registering invisible tool window failed, error = %08X\n", dwErr); 669 535 } 670 536 else … … 697 563 if (dwErr != ERROR_SUCCESS) 698 564 vboxTrayDestroyToolWindow(); 699 return RTErrConvertFromWin32(dwErr); 565 566 int const rc = RTErrConvertFromWin32(dwErr); 567 568 if (RT_FAILURE(rc)) 569 VBoxTrayError("Could not create tool window, rc=%Rrc\n", rc); 570 571 return rc; 700 572 } 701 573 … … 782 654 } 783 655 } 784 return RTErrConvertFromWin32(dwErr); 656 657 int const rc = RTErrConvertFromWin32(dwErr); 658 659 if (RT_FAILURE(rc)) 660 VBoxTrayError("Could not setup seamless, rc=%Rrc\n", rc); 661 662 return rc; 785 663 } 786 664 … … 800 678 } 801 679 680 /** 681 * Main routine for starting / stopping all internal services. 682 * 683 * @returns VBox status code. 684 */ 802 685 static int vboxTrayServiceMain(void) 803 686 { 804 687 int rc = VINF_SUCCESS; 805 LogFunc(("Entering vboxTrayServiceMain\n"));688 VBoxTrayVerbose(2, "Entering main loop\n"); 806 689 807 690 g_hStopSem = CreateEvent(NULL, TRUE, FALSE, NULL); … … 816 699 * Start services listed in the vboxServiceTable. 817 700 */ 818 VBOX SERVICEENV svcEnv;701 VBOXTRAYSVCENV svcEnv; 819 702 svcEnv.hInstance = g_hInstance; 820 703 821 704 /* Initializes disp-if to default (XPDM) mode. */ 822 705 VBoxDispIfInit(&svcEnv.dispIf); /* Cannot fail atm. */ 823 706 #ifdef VBOX_WITH_WDDM 824 707 /* 825 708 * For now the display mode will be adjusted to WDDM mode if needed 826 709 * on display service initialization when it detects the display driver type. 827 710 */ 828 #endif 711 #endif 712 VBoxTrayHlpReportStatus(VBoxGuestFacilityStatus_Init); 829 713 830 714 /* Finally start all the built-in services! */ 831 715 rc = vboxTrayServicesStart(&svcEnv); 832 if (RT_FAILURE(rc)) 833 { 834 /* Terminate service if something went wrong. */ 835 vboxTrayServicesStop(&svcEnv); 836 } 837 else 716 if (RT_SUCCESS(rc)) 838 717 { 839 718 uint64_t const uNtVersion = RTSystemGetNtVersion(); 840 rc = vboxTrayCreateTrayIcon();841 719 if ( RT_SUCCESS(rc) 842 720 && uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(5, 0, 0)) /* Only for W2K and up ... */ … … 853 731 { 854 732 /* Report the host that we're up and running! */ 855 hlpReportStatus(VBoxGuestFacilityStatus_Active);733 VBoxTrayHlpReportStatus(VBoxGuestFacilityStatus_Active); 856 734 } 857 735 … … 957 835 LogFunc(("Returned from main loop, exiting ...\n")); 958 836 } 959 LogFunc(("Waiting for services to stop ...\n")); 960 vboxTrayServicesStop(&svcEnv); 837 961 838 } /* Services started */ 839 840 LogFunc(("Waiting for services to stop ...\n")); 841 842 VBoxTrayHlpReportStatus(VBoxGuestFacilityStatus_Terminating); 843 844 vboxTrayServicesStop(&svcEnv); 845 962 846 CloseHandle(g_hStopSem); 847 963 848 } /* Stop event created */ 964 849 965 vboxTrayRemoveTrayIcon(); 966 967 LogFunc(("Leaving with rc=%Rrc\n", rc)); 850 VBoxTrayVerbose(2, "Leaving main loop with %Rrc\n", rc); 968 851 return rc; 852 } 853 854 /** 855 * Attaches to a parent console (if any) or creates an own (dedicated) console window. 856 * 857 * @returns VBox status code. 858 */ 859 static int vboxTrayAttachConsole(void) 860 { 861 if (g_fHasConsole) /* Console already attached? Bail out. */ 862 return VINF_SUCCESS; 863 864 /* As we run with the WINDOWS subsystem, we need to either attach to or create an own console 865 * to get any stdout / stderr output. */ 866 bool fAllocConsole = false; 867 if (!AttachConsole(ATTACH_PARENT_PROCESS)) 868 fAllocConsole = true; 869 870 if (fAllocConsole) 871 { 872 if (!AllocConsole()) 873 VBoxTrayShowError("Unable to attach to or allocate a console!"); 874 /* Continue running. */ 875 } 876 877 RTFILE hStdIn; 878 RTFileFromNative(&hStdIn, (RTHCINTPTR)GetStdHandle(STD_INPUT_HANDLE)); 879 /** @todo Closing of standard handles not support via IPRT (yet). */ 880 RTStrmOpenFileHandle(hStdIn, "r", 0, &g_pStdIn); 881 882 RTFILE hStdOut; 883 RTFileFromNative(&hStdOut, (RTHCINTPTR)GetStdHandle(STD_OUTPUT_HANDLE)); 884 /** @todo Closing of standard handles not support via IPRT (yet). */ 885 RTStrmOpenFileHandle(hStdOut, "wt", 0, &g_pStdOut); 886 887 RTFILE hStdErr; 888 RTFileFromNative(&hStdErr, (RTHCINTPTR)GetStdHandle(STD_ERROR_HANDLE)); 889 RTStrmOpenFileHandle(hStdErr, "wt", 0, &g_pStdErr); 890 891 if (!fAllocConsole) /* When attaching to the parent console, make sure we start on a fresh line. */ 892 RTPrintf("\n"); 893 894 g_fHasConsole = true; 895 896 return VINF_SUCCESS; 897 } 898 899 /** 900 * Detaches from the (parent) console. 901 */ 902 static void vboxTrayDetachConsole() 903 { 904 g_fHasConsole = false; 905 } 906 907 /** 908 * Destroys VBoxTray. 909 * 910 * @returns RTEXITCODE_SUCCESS. 911 */ 912 static RTEXITCODE vboxTrayDestroy() 913 { 914 vboxTrayDetachConsole(); 915 916 /* Release instance mutex. */ 917 if (g_hMutexAppRunning != NULL) 918 { 919 CloseHandle(g_hMutexAppRunning); 920 g_hMutexAppRunning = NULL; 921 } 922 923 return RTEXITCODE_SUCCESS; 924 } 925 926 /** 927 * Prints the help to either a message box or a console (if attached). 928 * 929 * @returns RTEXITCODE_SYNTAX. 930 * @param cArgs Number of arguments given via argc. 931 * @param papszArgs Arguments given specified by \a cArgs. 932 */ 933 static RTEXITCODE vboxTrayPrintHelp(int cArgs, char **papszArgs) 934 { 935 RT_NOREF(cArgs); 936 937 char szServices[64] = { 0 }; 938 for (size_t i = 0; i < RT_ELEMENTS(g_aServices); i++) 939 { 940 char szName[RTTHREAD_NAME_LEN]; 941 int rc2 = RTStrCopy(szName, sizeof(szName), g_aServices[i].pDesc->pszName); 942 RTStrToLower(szName); /* To make it easier for users to recognize the service name via command line. */ 943 AssertRCBreak(rc2); 944 if (i > 0) 945 { 946 rc2 = RTStrCat(szServices, sizeof(szServices), ", "); 947 AssertRCBreak(rc2); 948 } 949 rc2 = RTStrCat(szServices, sizeof(szServices), szName); 950 AssertRCBreak(rc2); 951 } 952 953 VBoxTrayShowMsgBox(VBOX_PRODUCT " - " VBOX_VBOXTRAY_TITLE, 954 MB_ICONINFORMATION, 955 VBOX_PRODUCT " %s v%u.%u.%ur%u\n" 956 "Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n\n" 957 "Command Line Parameters:\n\n" 958 "-d, --debug\n" 959 " Enables debugging mode\n" 960 "-f, --foreground\n" 961 " Enables running in foreground\n" 962 "-l, --logfile <file>\n" 963 " Enables logging to a file\n" 964 "-v, --verbose\n" 965 " Increases verbosity\n" 966 "-V, --version\n" 967 " Displays version number and exit\n" 968 "-?, -h, --help\n" 969 " Displays this help text and exit\n" 970 "\n" 971 "Service parameters:\n\n" 972 "--enable-<service-name>\n" 973 " Enables the given service\n" 974 "--disable-<service-name>\n" 975 " Disables the given service\n" 976 "--only-<service-name>\n" 977 " Only starts the given service\n" 978 "\n" 979 "Examples:\n" 980 " %s -vvv --logfile C:\\Temp\\VBoxTray.log\n" 981 " %s --foreground -vvvv --only-draganddrop\n" 982 "\n" 983 "Available services: %s\n\n", 984 VBOX_VBOXTRAY_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV, 985 papszArgs[0], papszArgs[0], szServices); 986 987 vboxTrayDestroy(); 988 989 return RTEXITCODE_SYNTAX; 969 990 } 970 991 … … 977 998 if (RT_FAILURE(rc)) 978 999 return RTMsgInitFailure(rc); 1000 1001 /* If a debugger is present, we always want to attach a console. */ 1002 if (IsDebuggerPresent()) 1003 vboxTrayAttachConsole(); 979 1004 980 1005 /* … … 983 1008 static const RTGETOPTDEF s_aOptions[] = 984 1009 { 1010 { "--debug", 'd', RTGETOPT_REQ_NOTHING }, 1011 { "/debug", 'd', RTGETOPT_REQ_NOTHING }, 1012 { "--foreground", 'f', RTGETOPT_REQ_NOTHING }, 1013 { "/foreground", 'f', RTGETOPT_REQ_NOTHING }, 985 1014 { "--help", 'h', RTGETOPT_REQ_NOTHING }, 986 1015 { "-help", 'h', RTGETOPT_REQ_NOTHING }, … … 1006 1035 { 1007 1036 case 'h': 1008 hlpShowMessageBox(VBOX_PRODUCT " - " VBOX_VBOXTRAY_TITLE, 1009 MB_ICONINFORMATION, 1010 "-- " VBOX_PRODUCT " %s v%u.%u.%ur%u --\n\n" 1011 "Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n\n" 1012 "Command Line Parameters:\n\n" 1013 "-l, --logfile <file>\n" 1014 " Enables logging to a file\n" 1015 "-v, --verbose\n" 1016 " Increases verbosity\n" 1017 "-V, --version\n" 1018 " Displays version number and exit\n" 1019 "-?, -h, --help\n" 1020 " Displays this help text and exit\n" 1021 "\n" 1022 "Examples:\n" 1023 " %s -vvv\n", 1024 VBOX_VBOXTRAY_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV, 1025 papszArgs[0], papszArgs[0]); 1026 return RTEXITCODE_SUCCESS; 1037 return vboxTrayPrintHelp(cArgs, papszArgs); 1038 1039 case 'd': 1040 { 1041 /* ignore rc */ vboxTrayAttachConsole(); 1042 g_cVerbosity = 4; /* Set verbosity to level 4. */ 1043 break; 1044 } 1045 1046 case 'f': 1047 { 1048 /* ignore rc */ vboxTrayAttachConsole(); 1049 /* Don't increase verbosity automatically here. */ 1050 break; 1051 } 1027 1052 1028 1053 case 'l': 1054 { 1029 1055 if (*ValueUnion.psz == '\0') 1030 1056 szLogFile[0] = '\0'; … … 1033 1059 rc = RTPathAbs(ValueUnion.psz, szLogFile, sizeof(szLogFile)); 1034 1060 if (RT_FAILURE(rc)) 1035 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on log file path: %Rrc (%s)", 1036 rc, ValueUnion.psz); 1061 { 1062 int rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on log file path: %Rrc (%s)", 1063 rc, ValueUnion.psz); 1064 vboxTrayDestroy(); 1065 return rcExit; 1066 } 1037 1067 } 1038 1068 break; 1069 } 1039 1070 1040 1071 case 'v': … … 1043 1074 1044 1075 case 'V': 1045 hlpShowMessageBox(VBOX_VBOXTRAY_TITLE, MB_ICONINFORMATION,1046 "Version: %u.%u.%ur%u",1047 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);1048 return RTEXITCODE_SUCCESS;1076 VBoxTrayShowMsgBox(VBOX_PRODUCT " - " VBOX_VBOXTRAY_TITLE, 1077 MB_ICONINFORMATION, 1078 "%u.%u.%ur%u", VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); 1079 return vboxTrayDestroy(); 1049 1080 1050 1081 default: 1051 rc = RTGetOptPrintError(ch, &ValueUnion); 1052 break; 1053 } 1054 } 1055 1056 /* Note: Do not use a global namespace ("Global\\") for mutex name here, 1057 * will blow up NT4 compatibility! */ 1058 HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, VBOX_VBOXTRAY_TITLE); 1059 if ( hMutexAppRunning != NULL 1082 { 1083 const char *psz = ValueUnion.psz; 1084 size_t const cch = strlen(ValueUnion.psz); 1085 bool fFound = false; 1086 1087 if (cch > sizeof("--enable-") && !memcmp(psz, RT_STR_TUPLE("--enable-"))) 1088 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) 1089 if ((fFound = !RTStrICmp(psz + sizeof("--enable-") - 1, g_aServices[j].pDesc->pszName))) 1090 g_aServices[j].fEnabled = true; 1091 1092 if (cch > sizeof("--disable-") && !memcmp(psz, RT_STR_TUPLE("--disable-"))) 1093 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) 1094 if ((fFound = !RTStrICmp(psz + sizeof("--disable-") - 1, g_aServices[j].pDesc->pszName))) 1095 g_aServices[j].fEnabled = false; 1096 1097 if (cch > sizeof("--only-") && !memcmp(psz, RT_STR_TUPLE("--only-"))) 1098 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) 1099 { 1100 g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("--only-") - 1, g_aServices[j].pDesc->pszName); 1101 if (g_aServices[j].fEnabled) 1102 fFound = true; 1103 } 1104 1105 if (!fFound) 1106 { 1107 rc = vboxTrayServicesLazyPreInit(); 1108 if (RT_FAILURE(rc)) 1109 break; 1110 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) 1111 { 1112 rc = g_aServices[j].pDesc->pfnOption(NULL, cArgs, papszArgs, NULL); 1113 fFound = rc == VINF_SUCCESS; 1114 if (fFound) 1115 break; 1116 if (rc != -1) /* Means not parsed. */ 1117 break; 1118 } 1119 } 1120 if (!fFound) 1121 { 1122 RTGetOptPrintError(ch, &ValueUnion); /* Only shown on console. */ 1123 return vboxTrayPrintHelp(cArgs, papszArgs); 1124 } 1125 1126 continue; 1127 } 1128 } 1129 } 1130 1131 if (RT_FAILURE(rc)) 1132 { 1133 vboxTrayDestroy(); 1134 return RTEXITCODE_FAILURE; 1135 } 1136 1137 /** 1138 * VBoxTray already running? Bail out. 1139 * 1140 * Note: Do not use a global namespace ("Global\\") for mutex name here, 1141 * will blow up NT4 compatibility! 1142 */ 1143 g_hMutexAppRunning = CreateMutex(NULL, FALSE, VBOX_VBOXTRAY_TITLE); 1144 if ( g_hMutexAppRunning != NULL 1060 1145 && GetLastError() == ERROR_ALREADY_EXISTS) 1061 1146 { 1062 /* VBoxTray already running? Bail out. */ 1063 CloseHandle (hMutexAppRunning); 1064 hMutexAppRunning = NULL; 1065 return RTEXITCODE_SUCCESS; 1066 } 1147 VBoxTrayError(VBOX_VBOXTRAY_TITLE " already running!\n"); 1148 return vboxTrayDestroy(); 1149 } 1150 1151 /* Set the instance handle. */ 1152 #ifdef IPRT_NO_CRT 1153 Assert(g_hInstance == NULL); /* Make sure this isn't set before by WinMain(). */ 1154 g_hInstance = GetModuleHandleW(NULL); 1155 #endif 1067 1156 1068 1157 rc = VbglR3Init(); 1069 1158 if (RT_SUCCESS(rc)) 1070 1159 { 1071 rc = vboxTrayLogCreate(szLogFile[0] ? szLogFile : NULL);1160 rc = VBoxTrayLogCreate(szLogFile[0] ? szLogFile : NULL); 1072 1161 if (RT_SUCCESS(rc)) 1073 1162 { 1074 LogRel(("Verbosity level: %d\n", g_cVerbosity)); 1075 1076 /* Log the major windows NT version: */ 1077 uint64_t const uNtVersion = RTSystemGetNtVersion(); 1078 LogRel(("Windows version %u.%u build %u (uNtVersion=%#RX64)\n", RTSYSTEM_NT_VERSION_GET_MAJOR(uNtVersion), 1079 RTSYSTEM_NT_VERSION_GET_MINOR(uNtVersion), RTSYSTEM_NT_VERSION_GET_BUILD(uNtVersion), uNtVersion )); 1080 1081 /* Set the instance handle. */ 1082 #ifdef IPRT_NO_CRT 1083 Assert(g_hInstance == NULL); /* Make sure this isn't set before by WinMain(). */ 1084 g_hInstance = GetModuleHandleW(NULL); 1085 #endif 1086 hlpReportStatus(VBoxGuestFacilityStatus_Init); 1163 VBoxTrayInfo("Verbosity level: %d\n", g_cVerbosity); 1164 1087 1165 rc = vboxTrayCreateToolWindow(); 1166 if (RT_SUCCESS(rc)) 1167 rc = vboxTrayCreateTrayIcon(); 1168 1169 VBoxTrayHlpReportStatus(VBoxGuestFacilityStatus_PreInit); 1170 1088 1171 if (RT_SUCCESS(rc)) 1089 1172 { … … 1101 1184 1102 1185 rc = vboxDtInit(); 1103 if ( !RT_SUCCESS(rc))1186 if (RT_FAILURE(rc)) 1104 1187 { 1105 LogFlowFunc(("vboxDtInit failed, rc=%Rrc\n", rc));1106 1188 /* ignore the Dt Init failure. this can happen for < XP win that do not support WTS API 1107 1189 * in that case the session is treated as active connected to the physical console … … 1110 1192 } 1111 1193 1112 rc = VBoxAcquireGuestCaps(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0, true); 1113 if (!RT_SUCCESS(rc)) 1114 LogFlowFunc(("VBoxAcquireGuestCaps failed with rc=%Rrc, ignoring ...\n", rc)); 1115 1116 rc = vboxTraySetupSeamless(); /** @todo r=andy Do we really want to be this critical for the whole application? */ 1117 if (RT_SUCCESS(rc)) 1118 { 1119 rc = vboxTrayServiceMain(); 1120 if (RT_SUCCESS(rc)) 1121 hlpReportStatus(VBoxGuestFacilityStatus_Terminating); 1122 vboxTrayShutdownSeamless(); 1123 } 1194 VBoxAcquireGuestCaps(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0, true); 1195 1196 vboxTraySetupSeamless(); 1197 1198 rc = vboxTrayServiceMain(); 1199 /* Note: Do *not* overwrite rc in the following code, as this acts as the exit code. */ 1200 1201 vboxTrayShutdownSeamless(); 1124 1202 1125 1203 /* it should be safe to call vboxDtTerm even if vboxStInit above failed */ … … 1130 1208 1131 1209 VBoxCapsTerm(); 1132 1133 vboxTrayDestroyToolWindow(); 1134 } 1210 } 1211 1212 vboxTrayRemoveTrayIcon(); 1213 vboxTrayDestroyToolWindow(); 1214 1135 1215 if (RT_SUCCESS(rc)) 1136 hlpReportStatus(VBoxGuestFacilityStatus_Terminated); 1216 1217 VBoxTrayHlpReportStatus(VBoxGuestFacilityStatus_Terminated); 1137 1218 else 1138 { 1139 LogRel(("Error while starting, rc=%Rrc\n", rc)); 1140 hlpReportStatus(VBoxGuestFacilityStatus_Failed); 1141 } 1142 1143 LogRel(("Ended\n")); 1144 1145 vboxTrayLogDestroy(); 1219 VBoxTrayHlpReportStatus(VBoxGuestFacilityStatus_Failed); 1220 1221 VBoxTrayInfo("VBoxTray terminated with %Rrc\n", rc); 1222 1223 VBoxTrayLogDestroy(); 1146 1224 } 1147 1225 … … 1151 1229 VBoxTrayShowError("VbglR3Init failed: %Rrc\n", rc); 1152 1230 1153 /* Release instance mutex. */ 1154 if (hMutexAppRunning != NULL) 1155 { 1156 CloseHandle(hMutexAppRunning); 1157 hMutexAppRunning = NULL; 1158 } 1231 vboxTrayDestroy(); 1159 1232 1160 1233 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; … … 1213 1286 { 1214 1287 case TIMERID_VBOXTRAY_CHECK_HOSTVERSION: 1288 { 1215 1289 if (RT_SUCCESS(VBoxCheckHostVersion())) 1216 1290 { 1217 /* After successful run we don't need to check again. */1291 /* After a successful run we don't need to check again. */ 1218 1292 KillTimer(g_hwndToolWindow, TIMERID_VBOXTRAY_CHECK_HOSTVERSION); 1219 1293 } 1294 1220 1295 return 0; 1296 } 1221 1297 1222 1298 default:
Note:
See TracChangeset
for help on using the changeset viewer.