/** * Retrieves and clears the user credentials for logging into the guest OS. * * @returns IPRT status value * @param ppszUser Receives pointer of allocated user name string. * The returned pointer must be freed using VbglR3CredentialsDestroy(). * @param ppszPassword Receives pointer of allocated user password string. * The returned pointer must be freed using VbglR3CredentialsDestroy(). * @param ppszDomain Receives pointer of allocated domain name string. * The returned pointer must be freed using VbglR3CredentialsDestroy(). */ VBGLR3DECL(int) VbglR3CredentialsRetrieve(char **ppszUser, char **ppszPassword, char **ppszDomain) { AssertPtrReturn(ppszUser, VERR_INVALID_POINTER); AssertPtrReturn(ppszPassword, VERR_INVALID_POINTER); AssertPtrReturn(ppszDomain, VERR_INVALID_POINTER); VMMDevCredentials Req; RT_ZERO(Req); vmmdevInitRequest((VMMDevRequestHeader*)&Req, VMMDevReq_QueryCredentials); Req.u32Flags |= VMMDEV_CREDENTIALS_READ | VMMDEV_CREDENTIALS_CLEAR; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { rc = RTStrDupEx(ppszUser, Req.szUserName); if (RT_SUCCESS(rc)) { rc = RTStrDupEx(ppszPassword, Req.szPassword); if (RT_SUCCESS(rc)) { rc = RTStrDupEx(ppszDomain, Req.szDomain); if (RT_SUCCESS(rc)) return VINF_SUCCESS; RTStrFree(*ppszPassword); } RTStrFree(*ppszUser); } } return rc; }
/** * Checks registered modules for shared pages * * @returns IPRT status code. */ VBGLR3DECL(int) VbglR3CheckSharedModules() { VMMDevSharedModuleCheckRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_CheckSharedModules); return vbglR3GRPerform(&Req.header); }
/** * Retrieve mouse coordinates and features from the host. * * @remarks Ring-0. * @returns VBox status code. * * @param pfFeatures Where to store the mouse features. * @param px Where to store the X co-ordinate. * @param py Where to store the Y co-ordinate. */ DECLVBGL(int) VbglGetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py) { VMMDevReqMouseStatus Req; VBGLDRIVER *pDriver; int rc; rc = vbglGetDriver(&pDriver); if (RT_FAILURE(rc)) return rc; vmmdevInitRequest(&Req.header, VMMDevReq_GetMouseStatus); Req.mouseFeatures = 0; Req.pointerXPos = 0; Req.pointerYPos = 0; rc = vbglDriverIOCtl(pDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(Req)), &Req.header, sizeof(Req)); if (RT_FAILURE(rc)) return rc; if (RT_FAILURE(Req.header.rc)) return Req.header.rc; if (pfFeatures) *pfFeatures = Req.mouseFeatures; if (px) *px = Req.pointerXPos; if (py) *py = Req.pointerYPos; return VINF_SUCCESS; }
void WriteLog(char *pszStr, ...) { VMMDevReqLogString *pReq = (VMMDevReqLogString *)LogBuffer; int rc; /* open VBox guest driver */ if (gVBoxDriver == INVALID_HANDLE_VALUE) gVBoxDriver = CreateFile(VBOXGUEST_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (gVBoxDriver == INVALID_HANDLE_VALUE) return; va_list va; va_start(va, pszStr); vmmdevInitRequest(&pReq->header, VMMDevReq_LogString); vsprintf(pReq->szString, pszStr, va); pReq->header.size += strlen(pReq->szString); rc = VbglR3GRPerform(&pReq->header); va_end (va); return; }
/** * Reports a state change of a specific guest user. * * @returns IPRT status value * @param pszUser Guest user name to report state for. * @param pszDomain Domain the guest user's account is bound to. * @param enmState Guest user state to report. * @param puDetails Pointer to state details. Optional. * @param cbDetails Size (in bytes) of state details. Pass 0 * if puDetails is NULL. */ VBGLR3DECL(int) VbglR3GuestUserReportState(const char *pszUser, const char *pszDomain, VBoxGuestUserState enmState, uint8_t *puDetails, uint32_t cbDetails) { AssertPtrReturn(pszUser, VERR_INVALID_POINTER); /* pszDomain is optional. */ /* puDetails is optional. */ AssertReturn(cbDetails == 0 || puDetails != NULL, VERR_INVALID_PARAMETER); AssertReturn(cbDetails < 16U*_1M, VERR_OUT_OF_RANGE); uint32_t cbBase = sizeof(VMMDevReportGuestUserState); uint32_t cbUser = (uint32_t)strlen(pszUser) + 1; /* Include terminating zero */ uint32_t cbDomain = pszDomain ? strlen(pszDomain) + 1 /* Ditto */ : 0; /* Allocate enough space for all fields. */ uint32_t cbSize = cbBase + cbUser + cbDomain + cbDetails; VMMDevReportGuestUserState *pReport = (VMMDevReportGuestUserState *)RTMemAllocZ(cbSize); if (!pReport) return VERR_NO_MEMORY; int rc = vmmdevInitRequest(&pReport->header, VMMDevReq_ReportGuestUserState); if (RT_SUCCESS(rc)) { pReport->header.size = cbSize; pReport->status.state = enmState; pReport->status.cbUser = cbUser; pReport->status.cbDomain = cbDomain; pReport->status.cbDetails = cbDetails; /* * Note: cbOffDynamic contains the first dynamic array entry within * VBoxGuestUserStatus. * Therefore it's vital to *not* change the order of the struct members * without altering this code. Don't try this at home. */ uint32_t cbOffDynamic = RT_OFFSETOF(VBoxGuestUserStatus, szUser); /* pDynamic marks the beginning for the dynamically allocated areas. */ uint8_t *pDynamic = (uint8_t *)&pReport->status; pDynamic += cbOffDynamic; AssertPtr(pDynamic); memcpy(pDynamic, pszUser, cbUser); if (cbDomain) memcpy(pDynamic + cbUser, pszDomain, cbDomain); if (cbDetails) memcpy(pDynamic + cbUser + cbDomain, puDetails, cbDetails); rc = vbglR3GRPerform(&pReport->header); } RTMemFree(pReport); return rc; }
/** * Checks if page sharing is enabled. * * @returns true/false enabled/disabled */ VBGLR3DECL(bool) VbglR3PageSharingIsEnabled() { VMMDevPageSharingStatusRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_GetPageSharingStatus); int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) return Req.fEnabled; return false; }
VBGLR3DECL(int) VbglR3GetHostTime(PRTTIMESPEC pTime) { VMMDevReqHostTime Req; vmmdevInitRequest(&Req.header, VMMDevReq_GetHostTime); Req.time = UINT64_MAX; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) RTTimeSpecSetMilli(pTime, (int64_t)Req.time); return rc; }
/** * Terminate CPU hot plugging. * * This will disable the CPU hot plugging events. * * @returns VBox status. */ VBGLR3DECL(int) VbglR3CpuHotPlugTerm(void) { /* Clear the events. */ VbglR3CtlFilterMask(0, VMMDEV_EVENT_CPU_HOTPLUG); VMMDevCpuHotPlugStatusRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_SetCpuHotPlugStatus); Req.enmStatusType = VMMDevCpuStatusType_Disable; return vbglR3GRPerform(&Req.header); }
/** * Query the session ID of this VM. * * The session id is an unique identifier that gets changed for each VM start, * reset or restore. Useful for detection a VM restore. * * @returns IPRT status code. * @param pu64IdSession Session id (out). This is NOT changed on * failure, so the caller can depend on this to * deal with backward compatibility (see * VBoxServiceVMInfoWorker() for an example.) */ VBGLR3DECL(int) VbglR3GetSessionId(uint64_t *pu64IdSession) { VMMDevReqSessionId Req; vmmdevInitRequest(&Req.header, VMMDevReq_GetSessionId); Req.idSession = 0; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) *pu64IdSession = Req.idSession; return rc; }
/** * Unregisters a shared module for the VM * * @returns IPRT status code. * @param pszModuleName Module name * @param pszVersion Module version * @param GCBaseAddr Module base address * @param cbModule Module size */ VBGLR3DECL(int) VbglR3UnregisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule) { VMMDevSharedModuleUnregistrationRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_UnregisterSharedModule); Req.GCBaseAddr = GCBaseAddr; Req.cbModule = cbModule; if ( RTStrCopy(Req.szName, sizeof(Req.szName), pszModuleName) != VINF_SUCCESS || RTStrCopy(Req.szVersion, sizeof(Req.szVersion), pszVersion) != VINF_SUCCESS) { return VERR_BUFFER_OVERFLOW; } return vbglR3GRPerform(&Req.header); }
/** * Initialize CPU hot plugging. * * This will enable the CPU hot plugging events. * * @returns VBox status code. */ VBGLR3DECL(int) VbglR3CpuHotPlugInit(void) { int rc = VbglR3CtlFilterMask(VMMDEV_EVENT_CPU_HOTPLUG, 0); if (RT_FAILURE(rc)) return rc; VMMDevCpuHotPlugStatusRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_SetCpuHotPlugStatus); Req.enmStatusType = VMMDevCpuStatusType_Enable; rc = vbglR3GRPerform(&Req.header); if (RT_FAILURE(rc)) VbglR3CtlFilterMask(0, VMMDEV_EVENT_CPU_HOTPLUG); return rc; }
/** * Checks whether user credentials are available to the guest or not. * * @returns IPRT status value; VINF_SUCCESS if credentials are available, * VERR_NOT_FOUND if not. Otherwise an error is occurred. */ VBGLR3DECL(int) VbglR3CredentialsQueryAvailability(void) { VMMDevCredentials Req; RT_ZERO(Req); vmmdevInitRequest((VMMDevRequestHeader*)&Req, VMMDevReq_QueryCredentials); Req.u32Flags |= VMMDEV_CREDENTIALS_QUERYPRESENCE; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { if ((Req.u32Flags & VMMDEV_CREDENTIALS_PRESENT) == 0) rc = VERR_NOT_FOUND; } return rc; }
/** * dprintf worker using VBoxGuest.sys and VMMDevReq_LogString. */ static void WriteLog(const char *pszFormat, ...) { /* * Open VBox guest driver once. */ static HANDLE s_hVBoxGuest = INVALID_HANDLE_VALUE; HANDLE hVBoxGuest = s_hVBoxGuest; if (hVBoxGuest == INVALID_HANDLE_VALUE) { hVBoxGuest = CreateFile(VBOXGUEST_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (hVBoxGuest == INVALID_HANDLE_VALUE) return; s_hVBoxGuest = hVBoxGuest; } /* * We're apparently afraid of using stack here, so we use a static buffer * instead and pray we won't be here at the same time on two threads... */ static union { VMMDevReqLogString Req; uint8_t abBuf[1024]; } s_uBuf; vmmdevInitRequest(&s_uBuf.Req.header, VMMDevReq_LogString); va_list va; va_start(va, pszFormat); size_t cch = vsprintf(s_uBuf.Req.szString, pszFormat, va); va_end(va); s_uBuf.Req.header.size += (uint32_t)cch; if (s_uBuf.Req.header.size > sizeof(s_uBuf)) __debugbreak(); DWORD cbReturned; DeviceIoControl(hVBoxGuest, VBOXGUEST_IOCTL_VMMREQUEST(s_uBuf.Req.size), &s_uBuf.Req, s_uBuf.Req.header.size, &s_uBuf.Req, s_uBuf.Req.header.size, &cbReturned, NULL); }
/** * Query the current statistics update interval. * * @returns IPRT status code. * @param pcMsInterval Update interval in ms (out). */ VBGLR3DECL(int) VbglR3StatQueryInterval(PRTMSINTERVAL pcMsInterval) { VMMDevGetStatisticsChangeRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_GetStatisticsChangeRequest); Req.eventAck = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST; Req.u32StatInterval = 1; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { *pcMsInterval = Req.u32StatInterval * 1000; if (*pcMsInterval / 1000 != Req.u32StatInterval) *pcMsInterval = ~(RTMSINTERVAL)0; } return rc; }
/** * Reports the Guest Additions status of a certain facility to the host. * * @returns IPRT status value * @param enmFacility The facility to report the status on. * @param enmStatus The new status of the facility. * @param fReserved Reserved for future use (what?). */ VBGLR3DECL(int) VbglR3ReportAdditionsStatus(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatusCurrent, uint32_t fReserved) { VMMDevReportGuestStatus Report; RT_ZERO(Report); int rc = vmmdevInitRequest((VMMDevRequestHeader*)&Report, VMMDevReq_ReportGuestStatus); if (RT_SUCCESS(rc)) { Report.guestStatus.facility = enmFacility; Report.guestStatus.status = enmStatusCurrent; Report.guestStatus.flags = fReserved; rc = vbglR3GRPerform(&Report.header); } return rc; }
/** * Registers a new shared module for the VM * * @returns IPRT status code. * @param pszModuleName Module name * @param pszVersion Module version * @param GCBaseAddr Module base address * @param cbModule Module size * @param cRegions Number of shared region descriptors * @param pRegions Shared region(s) */ VBGLR3DECL(int) VbglR3RegisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule, unsigned cRegions, VMMDEVSHAREDREGIONDESC *pRegions) { VMMDevSharedModuleRegistrationRequest *pReq; int rc; /* Sanity check. */ AssertReturn(cRegions < VMMDEVSHAREDREGIONDESC_MAX, VERR_INVALID_PARAMETER); pReq = (VMMDevSharedModuleRegistrationRequest *)RTMemAllocZ(RT_OFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[cRegions])); AssertReturn(pReq, VERR_NO_MEMORY); vmmdevInitRequest(&pReq->header, VMMDevReq_RegisterSharedModule); pReq->header.size = RT_OFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[cRegions]); pReq->GCBaseAddr = GCBaseAddr; pReq->cbModule = cbModule; pReq->cRegions = cRegions; #ifdef RT_OS_WINDOWS # if ARCH_BITS == 32 pReq->enmGuestOS = VBOXOSFAMILY_Windows32; # else pReq->enmGuestOS = VBOXOSFAMILY_Windows64; # endif #else /** todo */ pReq->enmGuestOS = VBOXOSFAMILY_Unknown; #endif for (unsigned i = 0; i < cRegions; i++) pReq->aRegions[i] = pRegions[i]; if ( RTStrCopy(pReq->szName, sizeof(pReq->szName), pszModuleName) != VINF_SUCCESS || RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS) { rc = VERR_BUFFER_OVERFLOW; goto end; } rc = vbglR3GRPerform(&pReq->header); end: RTMemFree(pReq); return rc; }
/** * Checks if page sharing is enabled. * * @returns true/false enabled/disabled */ VBGLR3DECL(int) VbglR3PageIsShared(RTGCPTR pPage, bool *pfShared, uint64_t *puPageFlags) { #ifdef DEBUG VMMDevPageIsSharedRequest Req; vmmdevInitRequest(&Req.header, VMMDevReq_DebugIsPageShared); Req.GCPtrPage = pPage; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { *pfShared = Req.fShared; *puPageFlags = Req.uPageFlags; } return rc; #else return VERR_NOT_IMPLEMENTED; #endif }
VBGLR3DECL(int) VbglR3VrdpGetChangeRequest(bool *pfActive, uint32_t *puExperienceLevel) { VMMDevVRDPChangeRequest Req; RT_ZERO(Req); /* implicit padding */ vmmdevInitRequest(&Req.header, VMMDevReq_GetVRDPChangeRequest); //VMMDEV_REQ_HDR_INIT(&Req.header, sizeof(Req), VMMDevReq_GetVRDPChangeRequest); int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { *pfActive = Req.u8VRDPActive != 0; *puExperienceLevel = Req.u32VRDPExperienceLevel; } else { *pfActive = false; *puExperienceLevel = 0; } return rc; }
/** * Retrieve mouse coordinates and features from the host. * * @returns VBox status code. * * @param pfFeatures Where to store the mouse features. * @param px Where to store the X co-ordinate. * @param py Where to store the Y co-ordinate. */ VBGLR3DECL(int) VbglR3GetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py) { VMMDevReqMouseStatus Req; vmmdevInitRequest(&Req.header, VMMDevReq_GetMouseStatus); Req.mouseFeatures = 0; Req.pointerXPos = 0; Req.pointerYPos = 0; int rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { if (pfFeatures) *pfFeatures = Req.mouseFeatures; if (px) *px = Req.pointerXPos; if (py) *py = Req.pointerYPos; } return rc; }
/** * Waits for a CPU hot plugging event and retrieve the data associated with it. * * @returns VBox status code. * @param penmEventType Where to store the event type on success. * @param pidCpuCore Where to store the CPU core ID on success. * @param pidCpuPackage Where to store the CPU package ID on success. */ VBGLR3DECL(int) VbglR3CpuHotPlugWaitForEvent(VMMDevCpuEventType *penmEventType, uint32_t *pidCpuCore, uint32_t *pidCpuPackage) { AssertPtrReturn(penmEventType, VERR_INVALID_POINTER); AssertPtrReturn(pidCpuCore, VERR_INVALID_POINTER); AssertPtrReturn(pidCpuPackage, VERR_INVALID_POINTER); VBoxGuestWaitEventInfo waitEvent; waitEvent.u32TimeoutIn = RT_INDEFINITE_WAIT; waitEvent.u32EventMaskIn = VMMDEV_EVENT_CPU_HOTPLUG; waitEvent.u32Result = VBOXGUEST_WAITEVENT_ERROR; waitEvent.u32EventFlagsOut = 0; int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent)); if (RT_SUCCESS(rc)) { /* did we get the right event? */ if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_CPU_HOTPLUG) { VMMDevGetCpuHotPlugRequest Req; /* get the CPU hot plugging request */ vmmdevInitRequest(&Req.header, VMMDevReq_GetCpuHotPlugRequest); Req.idCpuCore = UINT32_MAX; Req.idCpuPackage = UINT32_MAX; Req.enmEventType = VMMDevCpuEventType_None; rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { *penmEventType = Req.enmEventType; *pidCpuCore = Req.idCpuCore; *pidCpuPackage = Req.idCpuPackage; return VINF_SUCCESS; } } else rc = VERR_TRY_AGAIN; } return rc; }
/** * Waits for a CPU hot plugging event and retrieve the data associated with it. * * @returns VBox status code. * @param penmEventType Where to store the event type on success. * @param pidCpuCore Where to store the CPU core ID on success. * @param pidCpuPackage Where to store the CPU package ID on success. */ VBGLR3DECL(int) VbglR3CpuHotPlugWaitForEvent(VMMDevCpuEventType *penmEventType, uint32_t *pidCpuCore, uint32_t *pidCpuPackage) { AssertPtrReturn(penmEventType, VERR_INVALID_POINTER); AssertPtrReturn(pidCpuCore, VERR_INVALID_POINTER); AssertPtrReturn(pidCpuPackage, VERR_INVALID_POINTER); uint32_t fEvents = 0; int rc = VbglR3WaitEvent(VMMDEV_EVENT_CPU_HOTPLUG, RT_INDEFINITE_WAIT, &fEvents); if (RT_SUCCESS(rc)) { /* did we get the right event? */ if (fEvents & VMMDEV_EVENT_CPU_HOTPLUG) { VMMDevGetCpuHotPlugRequest Req; /* get the CPU hot plugging request */ vmmdevInitRequest(&Req.header, VMMDevReq_GetCpuHotPlugRequest); Req.idCpuCore = UINT32_MAX; Req.idCpuPackage = UINT32_MAX; Req.enmEventType = VMMDevCpuEventType_None; rc = vbglR3GRPerform(&Req.header); if (RT_SUCCESS(rc)) { *penmEventType = Req.enmEventType; *pidCpuCore = Req.idCpuCore; *pidCpuPackage = Req.idCpuPackage; return VINF_SUCCESS; } } else rc = VERR_TRY_AGAIN; } else if (rc == VERR_TIMEOUT) /* just in case */ rc = VERR_TRY_AGAIN; return rc; }
/** * Report guest statistics. * * @returns IPRT status code. * @param pReq Request packet with statistics. */ VBGLR3DECL(int) VbglR3StatReport(VMMDevReportGuestStats *pReq) { vmmdevInitRequest(&pReq->header, VMMDevReq_ReportGuestStats); return vbglR3GRPerform(&pReq->header); }
/** * Thread function to wait for and process seamless mode change * requests */ unsigned __stdcall VBoxSeamlessThread(void *pInstance) { VBOXSEAMLESSCONTEXT *pCtx = (VBOXSEAMLESSCONTEXT *)pInstance; HANDLE gVBoxDriver = pCtx->pEnv->hDriver; bool fTerminate = false; VBoxGuestFilterMaskInfo maskInfo; DWORD cbReturned; BOOL fWasScreenSaverActive = FALSE, ret; maskInfo.u32OrMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; maskInfo.u32NotMask = 0; if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) { Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask - or) succeeded\n")); } else { Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n")); return 0; } do { /* wait for a seamless change event */ VBoxGuestWaitEventInfo waitEvent; waitEvent.u32TimeoutIn = 5000; waitEvent.u32EventMaskIn = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL)) { Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl succeeded\n")); /* are we supposed to stop? */ if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0) break; Log(("VBoxTray: VBoxSeamlessThread: checking event\n")); /* did we get the right event? */ if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST) { Log(("VBoxTray: VBoxTray: going to get seamless change information\n")); /* We got at least one event. Read the requested resolution * and try to set it until success. New events will not be seen * but a new resolution will be read in this poll loop. */ for (;;) { /* get the seamless change request */ VMMDevSeamlessChangeRequest seamlessChangeRequest = {0}; vmmdevInitRequest((VMMDevRequestHeader*)&seamlessChangeRequest, VMMDevReq_GetSeamlessChangeRequest); seamlessChangeRequest.eventAck = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; BOOL fSeamlessChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(seamlessChangeRequest)), &seamlessChangeRequest, sizeof(seamlessChangeRequest), &seamlessChangeRequest, sizeof(seamlessChangeRequest), &cbReturned, NULL); if (fSeamlessChangeQueried) { Log(("VBoxTray: VBoxSeamlessThread: mode change to %d\n", seamlessChangeRequest.mode)); switch(seamlessChangeRequest.mode) { case VMMDev_Seamless_Disabled: if (fWasScreenSaverActive) { Log(("VBoxTray: Re-enabling the screensaver\n")); ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0); if (!ret) Log(("VBoxTray: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError())); } PostMessage(ghwndToolWindow, WM_VBOX_SEAMLESS_DISABLE, 0, 0); break; case VMMDev_Seamless_Visible_Region: ret = SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fWasScreenSaverActive, 0); if (!ret) Log(("VBoxTray: SystemParametersInfo SPI_GETSCREENSAVEACTIVE failed with %d\n", GetLastError())); if (fWasScreenSaverActive) Log(("VBoxTray: Disabling the screensaver\n")); ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); if (!ret) Log(("VBoxTray: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError())); PostMessage(ghwndToolWindow, WM_VBOX_SEAMLESS_ENABLE, 0, 0); break; case VMMDev_Seamless_Host_Window: break; default: AssertFailed(); break; } break; } else { Log(("VBoxTray: VBoxSeamlessThread: error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n")); } /* sleep a bit to not eat too much CPU while retrying */ /* are we supposed to stop? */ if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 50) == WAIT_OBJECT_0) { fTerminate = true; break; } } } } else { Log(("VBoxTray: VBoxTray: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n")); /* sleep a bit to not eat too much CPU in case the above call always fails */ if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0) { fTerminate = true; break; } } } while (!fTerminate); maskInfo.u32OrMask = 0; maskInfo.u32NotMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) { Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask - not) succeeded\n")); } else { Log(("VBoxTray: VBoxSeamlessThread: DeviceIOControl(CtlMask) failed\n")); } Log(("VBoxTray: VBoxSeamlessThread: finished seamless change request thread\n")); return 0; }
/** * Thread function to wait for and process seamless mode change * requests */ static DECLCALLBACK(int) VBoxSeamlessWorker(void *pInstance, bool volatile *pfShutdown) { AssertPtrReturn(pInstance, VERR_INVALID_POINTER); LogFlowFunc(("pInstance=%p\n", pInstance)); /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); PVBOXSEAMLESSCONTEXT pCtx = (PVBOXSEAMLESSCONTEXT)pInstance; HANDLE gVBoxDriver = pCtx->pEnv->hDriver; VBoxGuestFilterMaskInfo maskInfo; DWORD cbReturned; BOOL fWasScreenSaverActive = FALSE, fRet; maskInfo.u32OrMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; maskInfo.u32NotMask = 0; if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) { DWORD dwErr = GetLastError(); LogRel(("Seamless: DeviceIOControl(CtlMask) failed with %ld, exiting ...\n", dwErr)); return RTErrConvertFromWin32(dwErr); } int rc = VINF_SUCCESS; for (;;) { /* wait for a seamless change event */ VBoxGuestWaitEventInfo waitEvent; waitEvent.u32TimeoutIn = 5000; waitEvent.u32EventMaskIn = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL)) { /* are we supposed to stop? */ if (*pfShutdown) break; /* did we get the right event? */ if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST) { /* We got at least one event. Read the requested resolution * and try to set it until success. New events will not be seen * but a new resolution will be read in this poll loop. */ for (;;) { /* get the seamless change request */ VMMDevSeamlessChangeRequest seamlessChangeRequest = {0}; vmmdevInitRequest((VMMDevRequestHeader*)&seamlessChangeRequest, VMMDevReq_GetSeamlessChangeRequest); seamlessChangeRequest.eventAck = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; BOOL fSeamlessChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(seamlessChangeRequest)), &seamlessChangeRequest, sizeof(seamlessChangeRequest), &seamlessChangeRequest, sizeof(seamlessChangeRequest), &cbReturned, NULL); if (fSeamlessChangeQueried) { LogFlowFunc(("Mode changed to %d\n", seamlessChangeRequest.mode)); switch(seamlessChangeRequest.mode) { case VMMDev_Seamless_Disabled: if (fWasScreenSaverActive) { LogRel(("Seamless: Re-enabling the screensaver\n")); fRet = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0); if (!fRet) LogRel(("Seamless: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %ld\n", GetLastError())); } PostMessage(g_hwndToolWindow, WM_VBOX_SEAMLESS_DISABLE, 0, 0); break; case VMMDev_Seamless_Visible_Region: fRet = SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fWasScreenSaverActive, 0); if (!fRet) LogRel(("Seamless: SystemParametersInfo SPI_GETSCREENSAVEACTIVE failed with %ld\n", GetLastError())); if (fWasScreenSaverActive) LogRel(("Seamless: Disabling the screensaver\n")); fRet = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); if (!fRet) LogRel(("Seamless: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %ld\n", GetLastError())); PostMessage(g_hwndToolWindow, WM_VBOX_SEAMLESS_ENABLE, 0, 0); break; case VMMDev_Seamless_Host_Window: break; default: AssertFailed(); break; } break; } else LogRel(("Seamless: DeviceIoControl(ChangeReq) failed with %ld\n", GetLastError())); if (*pfShutdown) break; /* sleep a bit to not eat too much CPU while retrying */ RTThreadSleep(10); } } } else { /* sleep a bit to not eat too much CPU in case the above call always fails */ RTThreadSleep(10); } if (*pfShutdown) break; } maskInfo.u32OrMask = 0; maskInfo.u32NotMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) LogRel(("Seamless: DeviceIOControl(CtlMask) failed with %ld\n", GetLastError())); LogFlowFuncLeaveRC(rc); return rc; }