VBoxTray.cpp revision e0791f3e14768aaf0020eb06cbb0ada32c52f3ce
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * VBoxTray - Guest Additions Tray Application
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Copyright (C) 2006-2011 Oracle Corporation
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * available from http://www.virtualbox.org. This file is free software;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * General Public License (GPL) as published by the Free Software
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync/*******************************************************************************
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync* Header Files *
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync*******************************************************************************/
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync/*******************************************************************************
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync* Internal Functions *
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync*******************************************************************************/
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic int vboxTrayCreateTrayIcon(void);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsyncstatic LRESULT CALLBACK vboxToolWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync/* Global message handler prototypes. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic int vboxTrayGlMsgTaskbarCreated(WPARAM lParam, LPARAM wParam);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync/*static int vboxTrayGlMsgShowBalloonMsg(WPARAM lParam, LPARAM wParam);*/
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync/*******************************************************************************
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync* Global Variables *
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync*******************************************************************************/
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync/* The service table. */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync "Shared Clipboard",
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync "Seamless Windows",
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync "Location Awareness",
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync/* The global message table. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic VBOXGLOBALMESSAGE s_vboxGlobalMessageTable[] =
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Windows specific stuff. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync "TaskbarCreated",
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* VBoxTray specific stuff. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /** @todo Add new messages here! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Gets called whenever the Windows main taskbar
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync * get (re-)created. Nice to install our tray icon.
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * @return IPRT status code.
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * @param wParam
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * @param lParam
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic int vboxTrayGlMsgTaskbarCreated(WPARAM wParam, LPARAM lParam)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync HICON hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_VIRTUALBOX));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Could not load tray icon, error %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Prepare the system tray icon. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync gNotifyIconData.cbSize = NOTIFYICONDATA_V1_SIZE; // sizeof(NOTIFYICONDATA);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync gNotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync gNotifyIconData.uCallbackMessage = WM_VBOXTRAY_TRAY_ICON;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync sprintf(gNotifyIconData.szTip, "%s Guest Additions %d.%d.%dr%d",
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync VBOX_PRODUCT, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Could not create tray icon, error = %08X\n", dwErr));
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* Remove the system tray icon and refresh system tray. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync HWND hTrayWnd = FindWindow("Shell_TrayWnd", NULL); /* We assume we only have one tray atm. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync HWND hTrayNotifyWnd = FindWindowEx(hTrayWnd, 0, "TrayNotifyWnd", NULL);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic int vboxTrayStartServices(VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync pEnv->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync /* Could not create event. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Starting %s ...\n", pTable->pszName));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync bool fStartThread = false;
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync rc = pTable->pfnInit (pEnv, &pTable->pInstance, &fStartThread);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Failed to initialize rc = %Rrc\n", rc));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync pTable->hThread = (HANDLE)_beginthreadex(NULL, /* security */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync 0, /* stacksize */
9562e2d410460d8fae06fa24297f172fee1d1995vboxsync 0, /* initflag */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Advance to next table element. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic void vboxTrayStopServices(VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Signal to all threads. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* There is a thread, wait for termination. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Advance to next table element. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic int vboxTrayRegisterGlobalMessages(PVBOXGLOBALMESSAGE pTable)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync if (pTable == NULL) /* No table to register? Skip. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Register global accessible window messages. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync pTable->uMsgID = RegisterWindowMessage(TEXT(pTable->pszName));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Registering global message \"%s\" failed, error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Advance to next table element. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic bool vboxTrayHandleGlobalMessages(PVBOXGLOBALMESSAGE pTable, UINT uMsg,
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync return false;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync return true;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Advance to next table element. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync return false;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Open VBox guest driver. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync LogRel(("VBoxTray: Could not open VirtualBox Guest Additions driver! Please install / start it first! Error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic void vboxTrayCloseBaseDriver(void)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Destroy the tool window. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync UnregisterClass("VBoxTrayToolWndClass", ghInstance);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Create a custom window class. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync windowClass.lpfnWndProc = (WNDPROC)vboxToolWndProc;
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync windowClass.lpszClassName = "VBoxTrayToolWndClass";
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Registering invisible tool window failed, error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Create our (invisible) tool window.
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Note: The window name ("VBoxTrayToolWnd") and class ("VBoxTrayToolWndClass") is
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * needed for posting globally registered messages to VBoxTray and must not be
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * changed! Otherwise things get broken!
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync ghwndToolWindow = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync -200, -200, 100, 100, NULL, NULL, ghInstance, NULL);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Creating invisible tool window failed, error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Reload the cursor(s). */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Invisible tool window handle = %p\n", ghwndToolWindow));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Windows version %ld.%ld\n", info.dwMajorVersion, info.dwMinorVersion));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* We need to setup a security descriptor to allow other processes modify access to the seamless notification event semaphore. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync InitializeSecurityDescriptor(SecAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync fRC = SetSecurityDescriptorDacl(SecAttr.lpSecurityDescriptor, TRUE, 0, FALSE);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: SetSecurityDescriptorDacl failed with last error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* For Vista and up we need to change the integrity of the security descriptor, too. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync BOOL (WINAPI * pfnConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR StringSecurityDescriptor, DWORD StringSDRevision, PSECURITY_DESCRIPTOR *SecurityDescriptor, PULONG SecurityDescriptorSize);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Loading module ADVAPI32.DLL failed with last error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync *(uintptr_t *)&pfnConvertStringSecurityDescriptorToSecurityDescriptorA = (uintptr_t)GetProcAddress(hModule, "ConvertStringSecurityDescriptorToSecurityDescriptorA");
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: pfnConvertStringSecurityDescriptorToSecurityDescriptorA = %x\n", pfnConvertStringSecurityDescriptorToSecurityDescriptorA));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync if (pfnConvertStringSecurityDescriptorToSecurityDescriptorA)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync fRC = pfnConvertStringSecurityDescriptorToSecurityDescriptorA("S:(ML;;NW;;;LW)", /* this means "low integrity" */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: ConvertStringSecurityDescriptorToSecurityDescriptorA failed with last error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync fRC = GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: GetSecurityDescriptorSacl failed with last error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync fRC = SetSecurityDescriptorSacl(SecAttr.lpSecurityDescriptor, TRUE, pSacl, FALSE);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: SetSecurityDescriptorSacl failed with last error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync && gMajorVersion >= 5) /* Only for W2K and up ... */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync ghSeamlessNotifyEvent = CreateEvent(&SecAttr, FALSE, FALSE, VBOXHOOK_GLOBAL_EVENT_NAME);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: CreateEvent for Seamless failed, last error = %08X\n", dwErr));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic void vboxTrayShutdownSeamless(void)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic int vboxTrayServiceMain(void)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: CreateEvent for stopping VBoxTray failed, rc=%Rrc\n", rc));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Start services listed in the vboxServiceTable.
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Initializes disp-if to default (XPDM) mode. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync VBoxDispIfInit(&svcEnv.dispIf); /* Cannot fail atm. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * For now the display mode will be adjusted to WDDM mode if needed
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * on display service initialization when it detects the display driver type.
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Finally start all the built-in services! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync rc = vboxTrayStartServices(&svcEnv, vboxServiceTable);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Terminate service if something went wrong. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync && gMajorVersion >= 5) /* Only for W2K and up ... */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* We're ready to create the tooltip balloon.
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Check in 10 seconds (@todo make seconds configurable) ... */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Do the Shared Folders auto-mounting stuff. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Report the host that we're up and running! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Boost thread priority to make sure we wake up early for seamless window notifications
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * (not sure if it actually makes any difference though). */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Main execution loop
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Wait for the stop semaphore to be posted or a window event to arrive
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync HANDLE hWaitEvent[2] = { ghStopSem, ghSeamlessNotifyEvent };
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync if (0 == ghSeamlessNotifyEvent) /* If seamless mode is not active / supported, reduce event array count. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Number of events to wait in main loop: %ld\n", dwEventCount));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync while (true)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync DWORD waitResult = MsgWaitForMultipleObjectsEx(dwEventCount, hWaitEvent, 500, QS_ALLINPUT, 0);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Only enable for message debugging, lots of traffic! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync //Log(("VBoxTray: Wait result = %ld\n", waitResult));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync && ghSeamlessNotifyEvent != 0) /* Only jump in, if seamless is active! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* seamless window notification */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* timeout or a window message, handle it */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Returned from main loop, exiting ...\n"));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Waiting for services to stop ...\n"));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync } /* Services started */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync } /* Stop event created */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Leaving vboxTrayServiceMain with rc=%Rrc\n", rc));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Main function
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncint APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, "VBoxTray");
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Close the mutex for this application instance. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync LogRel(("VBoxTray: %s r%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Save instance handle. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync hlpReportStatus(VBoxGuestFacilityStatus_Terminating);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync hlpReportStatus(VBoxGuestFacilityStatus_Terminated);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync LogRel(("VBoxTray: Error while starting, rc=%Rrc\n", rc));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Release instance mutex. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * Window procedure for our tool window
6728a36898fd2be125a28e84d2115d19aa4923edvboxsyncstatic LRESULT CALLBACK vboxToolWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync int rc = vboxTrayRegisterGlobalMessages(&s_vboxGlobalMessageTable[0]);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync Log(("VBoxTray: Error registering global window messages, rc=%Rrc\n", rc));
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync KillTimer(ghwndToolWindow, TIMERID_VBOXTRAY_CHECK_HOSTVERSION);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* After successful run we don't need to check again. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync KillTimer(ghwndToolWindow, TIMERID_VBOXTRAY_CHECK_HOSTVERSION);
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync break; /* Make sure other timers get processed the usual way! */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Handle all globally registered window messages. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync if (vboxTrayHandleGlobalMessages(&s_vboxGlobalMessageTable[0], uMsg,
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync return 0; /* We handled the message. @todo Add return value!*/
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync break; /* We did not handle the message, dispatch to DefWndProc. */
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync /* Only if message was *not* handled by our switch above, dispatch
6728a36898fd2be125a28e84d2115d19aa4923edvboxsync * to DefWindowProc. */