VBoxTray.cpp revision 52fd478d45eb6613a66d8ecff00412452a070ee6
/* $Id$ */
/** @file
* VBoxTray - Guest Additions Tray Application
*/
/*
* Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <package-generated.h>
#include "product-generated.h"
#include "VBoxTray.h"
#include "VBoxTrayMsg.h"
#include "VBoxHelpers.h"
#include "VBoxSeamless.h"
#include "VBoxClipboard.h"
#include "VBoxDisplay.h"
#include "VBoxVRDP.h"
#include "VBoxHostVersion.h"
#include "VBoxSharedFolders.h"
#ifdef VBOX_WITH_DRAG_AND_DROP
# include "VBoxDnD.h"
#endif
#include "VBoxIPC.h"
#include "VBoxLA.h"
#include <VBoxHook.h>
#include "resource.h"
#include <malloc.h>
#include <VBoxGuestInternal.h>
#include <sddl.h>
#include <iprt/buildconfig.h>
#ifdef DEBUG
# define LOG_ENABLED
# define LOG_GROUP LOG_GROUP_DEFAULT
#endif
/* Default desktop state tracking */
#include <Wtsapi32.h>
/*
* St (session [state] tracking) functionality API
*
* !!!NOTE: this API is NOT thread-safe!!!
* it is supposed to be called & used from within the window message handler thread
* of the window passed to vboxStInit */
static void vboxStTerm(void);
/* @returns true on "IsActiveConsole" state change */
static BOOL vboxStIsActiveConsole();
/*
* Dt (desktop [state] tracking) functionality API
*
* !!!NOTE: this API is NOT thread-safe!!!
* */
static int vboxDtInit();
static void vboxDtTerm();
/* @returns true on "IsInputDesktop" state change */
static BOOL vboxDtHandleEvent();
/* @returns true iff the application (VBoxTray) desktop is input */
static BOOL vboxDtIsInputDesktop();
static HANDLE vboxDtGetNotifyEvent();
/* caps API */
#define VBOXCAPS_ENTRY_IDX_SEAMLESS 0
#define VBOXCAPS_ENTRY_IDX_GRAPHICS 1
#define VBOXCAPS_ENTRY_IDX_COUNT 2
typedef enum VBOXCAPS_ENTRY_FUNCSTATE
{
/* the cap is unsupported */
/* the cap is supported */
/* the cap functionality is started, it can be disabled however if its AcState is not ACQUIRED */
static int VBoxCapsInit();
static int VBoxCapsReleaseAll();
static void VBoxCapsTerm();
static int VBoxCapsAcquireAllSupported();
/* console-related caps API */
static BOOL VBoxConsoleIsAllowed();
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int vboxTrayCreateTrayIcon(void);
/* Global message handler prototypes. */
/*static int vboxTrayGlMsgShowBalloonMsg(WPARAM lParam, LPARAM wParam);*/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/* The service table. */
static VBOXSERVICEINFO vboxServiceTable[] =
{
{
"Display",
NULL /* pfnStop */,
},
{
"Shared Clipboard",
NULL /* pfnStop */,
},
{
"Seamless Windows",
NULL /* pfnStop */,
},
{
"VRDP",
NULL /* pfnStop */,
},
{
"IPC",
},
{
"Location Awareness",
NULL /* pfnStop */,
},
#ifdef VBOX_WITH_DRAG_AND_DROP
{
"Drag and Drop",
},
#endif
{
}
};
/* The global message table. */
static VBOXGLOBALMESSAGE s_vboxGlobalMessageTable[] =
{
/* Windows specific stuff. */
{
"TaskbarCreated",
},
/* VBoxTray specific stuff. */
/** @todo Add new messages here! */
{
}
};
/**
* Gets called whenever the Windows main taskbar
* get (re-)created. Nice to install our tray icon.
*
* @return IPRT status code.
* @param wParam
* @param lParam
*/
{
return vboxTrayCreateTrayIcon();
}
static int vboxTrayCreateTrayIcon(void)
{
{
return RTErrConvertFromWin32(dwErr);
}
/* Prepare the system tray icon. */
int rc = VINF_SUCCESS;
{
}
if (hIcon)
return rc;
}
static void vboxTrayRemoveTrayIcon()
{
if (gNotifyIconData.cbSize > 0)
{
/* Remove the system tray icon and refresh system tray. */
if (hTrayWnd)
{
if (hTrayNotifyWnd)
}
}
}
{
Log(("Starting services ...\n"));
/** @todo Use IPRT events here. */
if (!pEnv->hStopEvent)
{
/* Could not create event. */
return VERR_NOT_SUPPORTED;
}
while ( pTable
{
int rc = VINF_SUCCESS;
bool fStartThread = false;
if (RT_FAILURE(rc))
{
LogRel(("Failed to initialize service \"%s\", rc=%Rrc\n",
}
else
{
&& fStartThread)
{
unsigned threadid;
/** @todo Use RTThread* here. */
0, /* stacksize */
0, /* initflag */
&threadid);
}
if (RT_SUCCESS(rc))
else
{
Log(("Failed to start the thread\n"));
if (pTable->pfnDestroy)
}
}
/* Advance to next table element. */
pTable++;
}
return VINF_SUCCESS;
}
{
if (!pEnv->hStopEvent)
return;
/* Signal to all threads. */
while ( pCurTable
{
/* Advance to next table element. */
pCurTable++;
}
while ( pCurTable
{
{
{
/* There is a thread, wait for termination. */
/** @todo Use RTThread* here. */
/** @todo Don't wait forever here. Use a sensible default. */
/** @todo Dito. */
}
if (pCurTable->pfnDestroy)
}
/* Advance to next table element. */
pCurTable++;
}
}
{
int rc = VINF_SUCCESS;
return rc;
&& RT_SUCCESS(rc))
{
/* Register global accessible window messages. */
{
}
/* Advance to next table element. */
pTable++;
}
return rc;
}
{
return false;
{
{
if (pTable->pfnHandler)
return true;
}
/* Advance to next table element. */
pTable++;
}
return false;
}
static int vboxTrayOpenBaseDriver(void)
{
/* Open VBox guest driver. */
NULL,
NULL);
if (ghVBoxDriver == INVALID_HANDLE_VALUE)
{
dwErr = GetLastError();
LogRel(("Could not open VirtualBox Guest Additions driver! Please install / start it first! Error = %08X\n", dwErr));
}
return RTErrConvertFromWin32(dwErr);
}
static void vboxTrayCloseBaseDriver(void)
{
if (ghVBoxDriver)
{
ghVBoxDriver = NULL;
}
}
/**
* Release logger callback.
*
* @return IPRT status code.
* @param pLoggerRelease
* @param enmPhase
* @param pfnLog
*/
static void vboxTrayLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
{
/* Some introductory information. */
static RTTIMESPEC s_TimeSpec;
char szTmp[256];
if (enmPhase == RTLOGPHASE_BEGIN)
switch (enmPhase)
{
case RTLOGPHASE_BEGIN:
{
"VBoxTray %s r%s %s (%s %s) release log\n"
"Log opened %s\n",
/* the package type is interesting for Linux distributions */
char szExecName[RTPATH_MAX];
"Executable: %s\n"
"Process ID: %u\n"
"Package type: %s"
#ifdef VBOX_OSE
" (OSE)"
#endif
"\n",
RTProcSelf(),
break;
}
case RTLOGPHASE_PREROTATE:
break;
case RTLOGPHASE_POSTROTATE:
break;
case RTLOGPHASE_END:
break;
default:
/* nothing */;
}
}
/**
* Creates the default release logger outputting to the specified file.
* Pass NULL for disabled logging.
*
* @return IPRT status code.
* @param pszLogFile Filename for log output. Optional.
*/
static int vboxTrayLogCreate(const char *pszLogFile)
{
/* Create release logger (stdout + file). */
static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
#endif
#ifdef DEBUG
"all.e.l.f",
"VBOXTRAY_LOG",
#else
"all",
"VBOXTRAY_RELEASE_LOG",
#endif
if (RT_SUCCESS(rc))
{
#ifdef DEBUG
#else
/* Register this logger as the release logger. */
#endif
/* Explicitly flush the log in case of VBOXTRAY_RELEASE_LOG=buffered. */
}
else
return rc;
}
static void vboxTrayLogDestroy(void)
{
}
static void vboxTrayDestroyToolWindow(void)
{
if (ghwndToolWindow)
{
Log(("Destroying tool window ...\n"));
/* Destroy the tool window. */
}
}
static int vboxTrayCreateToolWindow(void)
{
/* Create a custom window class. */
WNDCLASS windowClass = {0};
if (!RegisterClass(&windowClass))
{
dwErr = GetLastError();
}
else
{
/*
* Create our (invisible) tool window.
* Note: The window name ("VBoxTrayToolWnd") and class ("VBoxTrayToolWndClass") is
* needed for posting globally registered messages to VBoxTray and must not be
* changed! Otherwise things get broken!
*
*/
"VBoxTrayToolWndClass", "VBoxTrayToolWnd",
if (!ghwndToolWindow)
{
dwErr = GetLastError();
}
else
{
/* Reload the cursor(s). */
}
}
if (dwErr != ERROR_SUCCESS)
return RTErrConvertFromWin32(dwErr);
}
static int vboxTraySetupSeamless(void)
{
if (GetVersionEx(&info))
{
}
/* We need to setup a security descriptor to allow other processes modify access to the seamless notification event semaphore. */
if (!fRC)
{
dwErr = GetLastError();
}
else
{
/* For Vista and up we need to change the integrity of the security descriptor, too. */
if (gMajorVersion >= 6)
{
BOOL (WINAPI * pfnConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR StringSecurityDescriptor, DWORD StringSDRevision, PSECURITY_DESCRIPTOR *SecurityDescriptor, PULONG SecurityDescriptorSize);
Log(("pfnConvertStringSecurityDescriptorToSecurityDescriptorA = %x\n", pfnConvertStringSecurityDescriptorToSecurityDescriptorA));
{
fRC = pfnConvertStringSecurityDescriptorToSecurityDescriptorA("S:(ML;;NW;;;LW)", /* this means "low integrity" */
if (!fRC)
{
dwErr = GetLastError();
Log(("ConvertStringSecurityDescriptorToSecurityDescriptorA failed with last error = %08X\n", dwErr));
}
else
{
if (!fRC)
{
dwErr = GetLastError();
}
else
{
if (!fRC)
{
dwErr = GetLastError();
}
}
}
}
}
if ( dwErr == ERROR_SUCCESS
{
if (ghSeamlessWtNotifyEvent == NULL)
{
dwErr = GetLastError();
}
if (ghSeamlessKmNotifyEvent == NULL)
{
dwErr = GetLastError();
}
}
}
return RTErrConvertFromWin32(dwErr);
}
static void vboxTrayShutdownSeamless(void)
{
{
}
{
}
}
static void VBoxTrayCheckDt()
{
if (vboxDtHandleEvent())
{
if (!VBoxConsoleIsAllowed() != !fOldAllowedState)
}
}
static int vboxTrayServiceMain(void)
{
int rc = VINF_SUCCESS;
Log(("Entering vboxTrayServiceMain\n"));
{
}
else
{
/*
* Start services listed in the vboxServiceTable.
*/
/* Initializes disp-if to default (XPDM) mode. */
#ifdef VBOX_WITH_WDDM
/*
* For now the display mode will be adjusted to WDDM mode if needed
* on display service initialization when it detects the display driver type.
*/
#endif
/* Finally start all the built-in services! */
if (RT_FAILURE(rc))
{
/* Terminate service if something went wrong. */
}
else
{
rc = vboxTrayCreateTrayIcon();
if ( RT_SUCCESS(rc)
{
/* We're ready to create the tooltip balloon.
Check in 10 seconds (@todo make seconds configurable) ... */
10 * 1000, /* 10 seconds */
NULL /* No timerproc */);
}
if (RT_SUCCESS(rc))
{
/* Do the Shared Folders auto-mounting stuff. */
if (RT_SUCCESS(rc))
{
/* Report the host that we're up and running! */
}
}
if (RT_SUCCESS(rc))
{
/* Boost thread priority to make sure we wake up early for seamless window notifications
* (not sure if it actually makes any difference though). */
/*
* Main execution loop
* Wait for the stop semaphore to be posted or a window event to arrive
*/
DWORD dwEventCount = 0;
/* Check if seamless mode is not active and add seamless event to the list */
if (0 != ghSeamlessWtNotifyEvent)
{
}
if (0 != ghSeamlessKmNotifyEvent)
{
}
if (0 != vboxDtGetNotifyEvent())
{
}
while (true)
{
/* Only enable for message debugging, lots of traffic! */
//Log(("Wait result = %ld\n", waitResult));
if (waitResult == 0)
{
Log(("Event 'Exit' triggered\n"));
/* exit */
break;
}
else
{
{
if (hWaitEvent[waitResult])
{
{
Log(("Event 'Seamless' triggered\n"));
/* seamless window notification */
VBoxSeamlessCheckWindows(false);
}
{
Log(("Event 'Km Seamless' triggered\n"));
/* seamless window notification */
VBoxSeamlessCheckWindows(true);
}
{
Log(("Event 'Dt' triggered\n"));
}
}
}
if (!fHandled)
{
/* timeout or a window message, handle it */
{
#ifndef DEBUG_andy
#endif
{
Log(("WM_QUIT!\n"));
}
}
}
}
}
Log(("Returned from main loop, exiting ...\n"));
}
Log(("Waiting for services to stop ...\n"));
} /* Services started */
} /* Stop event created */
return rc;
}
/**
* Main function
*/
{
/* Note: Do not use a global namespace ("Global\\") for mutex name here,
* will blow up NT4 compatibility! */
if ( hMutexAppRunning != NULL
&& GetLastError() == ERROR_ALREADY_EXISTS)
{
/* VBoxTray already running? Bail out. */
return 0;
}
int rc = RTR3InitExeNoArguments(0);
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
rc = VbglR3Init();
if (RT_SUCCESS(rc))
rc = vboxTrayOpenBaseDriver();
}
if (RT_SUCCESS(rc))
{
/* Save instance handle. */
if (RT_SUCCESS(rc))
{
VBoxCapsInit();
if (!RT_SUCCESS(rc))
{
LogFlowFunc(("vboxStInit failed, rc %d\n"));
/* ignore the St Init failure. this can happen for < XP win that do not support WTS API
* in that case the session is treated as active connected to the physical console
* (i.e. fallback to the old behavior that was before introduction of VBoxSt) */
}
rc = vboxDtInit();
if (!RT_SUCCESS(rc))
{
LogFlowFunc(("vboxDtInit failed, rc %d\n"));
/* ignore the Dt Init failure. this can happen for < XP win that do not support WTS API
* in that case the session is treated as active connected to the physical console
* (i.e. fallback to the old behavior that was before introduction of VBoxSt) */
}
rc = VBoxAcquireGuestCaps(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0, true);
if (!RT_SUCCESS(rc))
{
}
rc = vboxTraySetupSeamless();
if (RT_SUCCESS(rc))
{
Log(("Init successful\n"));
rc = vboxTrayServiceMain();
if (RT_SUCCESS(rc))
}
/* it should be safe to call vboxDtTerm even if vboxStInit above failed */
vboxDtTerm();
/* it should be safe to call vboxStTerm even if vboxStInit above failed */
vboxStTerm();
VBoxCapsTerm();
}
if (RT_SUCCESS(rc))
}
if (RT_FAILURE(rc))
{
}
LogRel(("Ended\n"));
/* Release instance mutex. */
if (hMutexAppRunning != NULL)
{
}
VbglR3Term();
}
/**
* Window procedure for our tool window
*/
{
switch (uMsg)
{
case WM_CREATE:
{
Log(("Tool window created\n"));
if (RT_FAILURE(rc))
return 0;
}
case WM_CLOSE:
return 0;
case WM_DESTROY:
Log(("Tool window destroyed\n"));
return 0;
case WM_TIMER:
if (VBoxCapsCheckTimer(wParam))
return 0;
if (vboxDtCheckTimer(wParam))
return 0;
if (vboxStCheckTimer(wParam))
return 0;
switch (wParam)
{
if (RT_SUCCESS(VBoxCheckHostVersion()))
{
/* After successful run we don't need to check again. */
}
return 0;
default:
break;
}
break; /* Make sure other timers get processed the usual way! */
case WM_VBOXTRAY_TRAY_ICON:
switch (lParam)
{
case WM_LBUTTONDBLCLK:
break;
case WM_RBUTTONDOWN:
break;
}
return 0;
case WM_VBOX_SEAMLESS_ENABLE:
return 0;
case WM_VBOX_SEAMLESS_DISABLE:
return 0;
case WM_DISPLAYCHANGE:
case WM_VBOX_SEAMLESS_UPDATE:
VBoxSeamlessCheckWindows(true);
return 0;
return 0;
return 0;
case WM_WTSSESSION_CHANGE:
{
{
if (!VBoxConsoleIsAllowed() != !fOldAllowedState)
}
return 0;
}
default:
/* Handle all globally registered window messages. */
{
return 0; /* We handled the message. @todo Add return value!*/
}
break; /* We did not handle the message, dispatch to DefWndProc. */
}
/* Only if message was *not* handled by our switch above, dispatch
* to DefWindowProc. */
}
/* St (session [state] tracking) functionality API impl */
typedef struct VBOXST
{
BOOL (WINAPI * pfnWTSQuerySessionInformationA)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR *ppBuffer, DWORD *pBytesReturned);
} VBOXST;
static int vboxStCheckState()
{
int rc = VINF_SUCCESS;
if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState,
{
if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSClientProtocolType,
{
return VINF_SUCCESS;
}
}
else
{
}
/* failure branch, set to "console-active" state */
return rc;
}
{
if (RT_SUCCESS(rc))
{
(void **)&gVBoxSt.pfnWTSRegisterSessionNotification);
if (RT_SUCCESS(rc))
{
(void **)&gVBoxSt.pfnWTSUnRegisterSessionNotification);
if (RT_SUCCESS(rc))
{
(void **)&gVBoxSt.pfnWTSQuerySessionInformationA);
if (RT_FAILURE(rc))
LogFlowFunc(("WTSQuerySessionInformationA not found\n"));
}
else
LogFlowFunc(("WTSUnRegisterSessionNotification not found\n"));
}
else
LogFlowFunc(("WTSRegisterSessionNotification not found\n"));
if (RT_SUCCESS(rc))
{
else
{
if (dwErr == RPC_S_INVALID_BINDING)
{
rc = VINF_SUCCESS;
}
else
}
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
}
}
else
return rc;
}
static void vboxStTerm(void)
{
if (!gVBoxSt.hWTSAPIWnd)
{
LogFlowFunc(("vboxStTerm called for non-initialized St\n"));
return;
}
{
/* notification is not registered, just kill timer */
}
else
{
{
}
}
}
{
switch (val)
{
default:
return "Unknown";
}
}
{
return FALSE;
{
}
else
{
}
return TRUE;
}
{
return !vboxStIsActiveConsole() != !fOldIsActiveConsole;
}
static BOOL vboxStIsActiveConsole()
{
}
/*
* Dt (desktop [state] tracking) functionality API impl
*
* !!!NOTE: this API is NOT thread-safe!!!
* */
typedef struct VBOXDT
{
} VBOXDT;
static BOOL vboxDtCalculateIsInputDesktop()
{
if (hInput)
{
// DWORD dwThreadId = GetCurrentThreadId();
// HDESK hThreadDt = gVBoxDt.pfnGetThreadDesktop(dwThreadId);
// if (hThreadDt)
// {
fIsInputDt = TRUE;
// }
// else
// {
// DWORD dwErr = GetLastError();
// LogFlowFunc(("pfnGetThreadDesktop for Seamless failed, last error = %08X\n", dwErr));
// }
}
else
{
// LogFlowFunc(("pfnOpenInputDesktop for Seamless failed, last error = %08X\n", dwErr));
}
return fIsInputDt;
}
{
return FALSE;
return TRUE;
}
static int vboxDtInit()
{
int rc = VINF_SUCCESS;
if (GetVersionEx(&info))
{
}
{
/* Load the hook dll and resolve the necessary entry points. */
if (RT_SUCCESS(rc))
{
(void **)&gVBoxDt.pfnVBoxHookInstallActiveDesktopTracker);
if (RT_SUCCESS(rc))
{
(void **)&gVBoxDt.pfnVBoxHookRemoveActiveDesktopTracker);
if (RT_FAILURE(rc))
LogFlowFunc(("VBoxHookRemoveActiveDesktopTracker not found\n"));
}
else
LogFlowFunc(("VBoxHookInstallActiveDesktopTracker not found\n"));
if (RT_SUCCESS(rc))
{
/* Try get the system APIs we need. */
if (!gVBoxDt.pfnGetThreadDesktop)
{
LogFlowFunc(("GetThreadDesktop not found\n"));
}
if (!gVBoxDt.pfnOpenInputDesktop)
{
LogFlowFunc(("OpenInputDesktop not found\n"));
}
if (!gVBoxDt.pfnCloseDesktop)
{
LogFlowFunc(("CloseDesktop not found\n"));
}
if (RT_SUCCESS(rc))
{
/* For Vista and up we need to change the integrity of the security descriptor, too. */
if (gMajorVersion >= 6)
{
if (!fRc)
{
}
}
if (!fRc)
{
{
}
}
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
}
else
{
}
}
else
{
}
return rc;
}
static void vboxDtTerm()
{
if (!gVBoxDt.hLdrModHook)
return;
}
/* @returns true on "IsInputDesktop" state change */
static BOOL vboxDtHandleEvent()
{
}
static HANDLE vboxDtGetNotifyEvent()
{
return gVBoxDt.hNotifyEvent;
}
/* @returns true iff the application (VBoxTray) desktop is input */
static BOOL vboxDtIsInputDesktop()
{
return gVBoxDt.fIsInputDesktop;
}
/* we need to perform Acquire/Release using the file handled we use for rewuesting events from VBoxGuest
* otherwise Acquisition mechanism will treat us as different client and will not propagate necessary requests
* */
{
DWORD cbReturned = 0;
Info.enmFlags = fCfg ? VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE : VBOXGUESTCAPSACQUIRE_FLAGS_NONE;
if (!DeviceIoControl(ghVBoxDriver, VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE, &Info, sizeof(Info), &Info, sizeof(Info), &cbReturned, NULL))
{
return RTErrConvertFromWin32(LastErr);
}
if (!RT_SUCCESS(rc))
{
return rc;
}
return rc;
}
typedef enum VBOXCAPS_ENTRY_ACSTATE
{
/* the given cap is released */
/* the given cap acquisition is in progress */
/* the given cap is acquired */
struct VBOXCAPS_ENTRY;
struct VBOXCAPS;
typedef DECLCALLBACKPTR(void, PFNVBOXCAPS_ENTRY_ON_ENABLE)(struct VBOXCAPS *pConsole, struct VBOXCAPS_ENTRY *pCap, BOOL fEnabled);
typedef struct VBOXCAPS_ENTRY
{
typedef struct VBOXCAPS
{
} VBOXCAPS;
static DECLCALLBACK(void) vboxCapsOnEnableSeamles(struct VBOXCAPS *pConsole, struct VBOXCAPS_ENTRY *pCap, BOOL fEnabled)
{
if (fEnabled)
{
Log(("vboxCapsOnEnableSeamles: ENABLED\n"));
}
else
{
Log(("vboxCapsOnEnableSeamles: DISABLED\n"));
Assert(pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_ACQUIRED || pCap->enmFuncState != VBOXCAPS_ENTRY_FUNCSTATE_STARTED);
}
}
{
Log(("vboxCapsEntryAcStateSet: new state enmAcState(%d); pCap: fCap(%d), iCap(%d), enmFuncState(%d), enmAcState(%d)\n",
return;
{
{
if (pCap->pfnOnEnable)
}
}
else if (enmOldAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED && pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
{
if (pCap->pfnOnEnable)
}
}
{
Log(("vboxCapsEntryFuncStateSet: new state enmAcState(%d); pCap: fCap(%d), iCap(%d), enmFuncState(%d), enmAcState(%d)\n",
return;
{
{
if (pCap->pfnOnEnable)
}
}
else if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED && enmOldFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
{
if (pCap->pfnOnEnable)
}
}
{
}
static int VBoxCapsInit()
{
return VINF_SUCCESS;
}
static int VBoxCapsReleaseAll()
{
Log(("VBoxCapsReleaseAll\n"));
int rc = VBoxAcquireGuestCaps(0, VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, false);
if (!RT_SUCCESS(rc))
{
return rc;
}
{
Log(("killing console timer\n"));
}
{
}
return rc;
}
static void VBoxCapsTerm()
{
}
{
}
{
}
{
return FALSE;
uint32_t u32AcquiredCaps = 0;
{
continue;
if (RT_SUCCESS(rc))
{
}
else
{
}
}
if (!fNeedNewTimer)
{
/* cleanup timer data */
}
return TRUE;
}
{
{
return VERR_INVALID_STATE;
}
{
}
return VINF_SUCCESS;
}
{
{
return VERR_INVALID_STATE;
}
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
if (rc != VERR_RESOURCE_BUSY)
{
return rc;
}
/* the cap was busy, most likely it is still used by other VBoxTray instance running in another session,
* queue the retry timer */
{
{
return RTErrConvertFromWin32(dwErr);
}
}
return rc;
}
static int VBoxCapsAcquireAllSupported()
{
Log(("VBoxCapsAcquireAllSupported\n"));
{
{
Log(("VBoxCapsAcquireAllSupported acquiring cap %d, state %d\n", i, pConsole->aCaps[i].enmFuncState));
}
else
{
LogFlowFunc(("VBoxCapsAcquireAllSupported: WARN: cap %d not supported, state %d\n", i, pConsole->aCaps[i].enmFuncState));
}
}
return VINF_SUCCESS;
}
static BOOL VBoxConsoleIsAllowed()
{
return vboxDtIsInputDesktop() && vboxStIsActiveConsole();
}
{
if (fEnable)
else
}
{
if (fSupported)
{
if (VBoxConsoleIsAllowed())
}
else
{
}
}
{
}
{
}