/** * Register active event listener for the selected VM. * * @param virtualBox ptr to IVirtualBox object * @param session ptr to ISession object * @param id identifies the machine to start */ static void registerActiveEventListener(IVirtualBox *virtualBox, ISession *session, BSTR machineId) { IConsole *console = NULL; HRESULT rc; rc = ISession_get_Console(session, &console); if ((SUCCEEDED(rc)) && console) { IEventSource *es = NULL; rc = IConsole_get_EventSource(console, &es); if (SUCCEEDED(rc) && es) { static const ULONG interestingEvents[] = { VBoxEventType_OnMousePointerShapeChanged, VBoxEventType_OnMouseCapabilityChanged, VBoxEventType_OnKeyboardLedsChanged, VBoxEventType_OnStateChanged, VBoxEventType_OnAdditionsStateChanged, VBoxEventType_OnNetworkAdapterChanged, VBoxEventType_OnSerialPortChanged, VBoxEventType_OnParallelPortChanged, VBoxEventType_OnStorageControllerChanged, VBoxEventType_OnMediumChanged, VBoxEventType_OnVRDEServerChanged, VBoxEventType_OnUSBControllerChanged, VBoxEventType_OnUSBDeviceStateChanged, VBoxEventType_OnSharedFolderChanged, VBoxEventType_OnRuntimeError, VBoxEventType_OnCanShowWindow, VBoxEventType_OnShowWindow }; SAFEARRAY *interestingEventsSA = NULL; IEventListenerDemo *consoleListener = NULL; /* The VirtualBox API expects enum values as VT_I4, which in the * future can be hopefully relaxed. */ interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, sizeof(interestingEvents) / sizeof(interestingEvents[0])); g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &interestingEvents, sizeof(interestingEvents)); consoleListener = calloc(1, sizeof(IEventListenerDemo)); if (consoleListener) { consoleListener->lpVtbl = &(g_IEventListenerDemoVtblInt.lpVtbl); #ifdef WIN32 CoCreateFreeThreadedMarshaler((IUnknown *)consoleListener, &consoleListener->pUnkMarshaler); #endif IEventListenerDemo_AddRef(consoleListener); rc = IEventSource_RegisterListener(es, (IEventListener *)consoleListener, ComSafeArrayAsInParam(interestingEventsSA), 1 /* active */); if (SUCCEEDED(rc)) { /* Just wait here for events, no easy way to do this better * as there's not much to do after this completes. */ printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); fflush(stdout); #ifdef WIN32 SetConsoleCtrlHandler(ctrlCHandler, TRUE); #else signal(SIGINT, (void (*)(int))ctrlCHandler); #endif while (!g_fStop) { g_pVBoxFuncs->pfnProcessEventQueue(250); } #ifdef WIN32 SetConsoleCtrlHandler(ctrlCHandler, FALSE); #else signal(SIGINT, SIG_DFL); #endif } else { printf("Failed to register event listener.\n"); } IEventSource_UnregisterListener(es, (IEventListener *)consoleListener); #ifdef WIN32 if (consoleListener->pUnkMarshaler) IUnknown_Release(consoleListener->pUnkMarshaler); #endif IEventListenerDemo_Release(consoleListener); } else { printf("Failed while allocating memory for console event listener.\n"); } g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA); IEventSource_Release(es); } else { printf("Failed to get the event source instance.\n"); } IConsole_Release(console); } }
/** * Initializes a file object but does *not* open the file on the guest * yet. This is done in the dedidcated openFile call. * * @return IPRT status code. * @param pConsole Pointer to console object. * @param pSession Pointer to session object. * @param uFileID Host-based file ID (part of the context ID). * @param openInfo File opening information. */ int GuestFile::init(Console *pConsole, GuestSession *pSession, ULONG uFileID, const GuestFileOpenInfo &openInfo) { LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n", pConsole, pSession, uFileID, openInfo.mFileName.c_str())); AssertPtrReturn(pConsole, VERR_INVALID_POINTER); AssertPtrReturn(pSession, VERR_INVALID_POINTER); /* Enclose the state transition NotReady->InInit->Ready. */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */); if (RT_SUCCESS(vrc)) { mSession = pSession; mData.mID = uFileID; mData.mInitialSize = 0; mData.mStatus = FileStatus_Undefined; mData.mOpenInfo = openInfo; unconst(mEventSource).createObject(); HRESULT hr = mEventSource->init(); if (FAILED(hr)) vrc = VERR_COM_UNEXPECTED; } if (RT_SUCCESS(vrc)) { try { GuestFileListener *pListener = new GuestFileListener(); ComObjPtr<GuestFileListenerImpl> thisListener; HRESULT hr = thisListener.createObject(); if (SUCCEEDED(hr)) hr = thisListener->init(pListener, this); if (SUCCEEDED(hr)) { com::SafeArray <VBoxEventType_T> eventTypes; eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged); eventTypes.push_back(VBoxEventType_OnGuestFileRead); eventTypes.push_back(VBoxEventType_OnGuestFileWrite); hr = mEventSource->RegisterListener(thisListener, ComSafeArrayAsInParam(eventTypes), TRUE /* Active listener */); if (SUCCEEDED(hr)) { vrc = baseInit(); if (RT_SUCCESS(vrc)) { mLocalListener = thisListener; } } else vrc = VERR_COM_UNEXPECTED; } else vrc = VERR_COM_UNEXPECTED; } catch(std::bad_alloc &) { vrc = VERR_NO_MEMORY; } } if (RT_SUCCESS(vrc)) { /* Confirm a successful initialization when it's the case. */ autoInitSpan.setSucceeded(); } else autoInitSpan.setFailed(); LogFlowFuncLeaveRC(vrc); return vrc; }
int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); LogFlowThisFuncEnter(); if (pSvcCbData->mParms < 3) return VERR_INVALID_PARAMETER; int vrc = VINF_SUCCESS; int idx = 1; /* Current parameter index. */ CALLBACKDATA_FILE_NOTIFY dataCb; /* pSvcCb->mpaParms[0] always contains the context ID. */ pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType); pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc); int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n", dataCb.uType, guestRc)); if (RT_FAILURE(guestRc)) { int rc2 = i_setFileStatus(FileStatus_Error, guestRc); AssertRC(rc2); rc2 = signalWaitEventInternal(pCbCtx, guestRc, NULL /* pPayload */); AssertRC(rc2); return VINF_SUCCESS; /* Report to the guest. */ } switch (dataCb.uType) { case GUEST_FILE_NOTIFYTYPE_ERROR: { int rc2 = i_setFileStatus(FileStatus_Error, guestRc); AssertRC(rc2); break; } case GUEST_FILE_NOTIFYTYPE_OPEN: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle); AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID), ("File ID %RU32 does not match context ID %RU32\n", mData.mID, VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID))); /* Set the process status. */ int rc2 = i_setFileStatus(FileStatus_Open, guestRc); AssertRC(rc2); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_CLOSE: { int rc2 = i_setFileStatus(FileStatus_Closed, guestRc); AssertRC(rc2); break; } case GUEST_FILE_NOTIFYTYPE_READ: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData, &dataCb.u.read.cbData); uint32_t cbRead = dataCb.u.read.cbData; AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent += cbRead; alock.release(); com::SafeArray<BYTE> data((size_t)cbRead); data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead); fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, cbRead, ComSafeArrayAsInParam(data)); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_WRITE: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent += dataCb.u.write.cbWritten; uint64_t uOffCurrent = mData.mOffCurrent; alock.release(); fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent, dataCb.u.write.cbWritten); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_SEEK: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent = dataCb.u.seek.uOffActual; alock.release(); fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, dataCb.u.seek.uOffActual, 0 /* Processed */); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_TELL: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent = dataCb.u.tell.uOffActual; alock.release(); fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, dataCb.u.tell.uOffActual, 0 /* Processed */); } else vrc = VERR_NOT_SUPPORTED; break; } default: vrc = VERR_NOT_SUPPORTED; break; } if (RT_SUCCESS(vrc)) { GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb)); int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload); AssertRC(rc2); } LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n", dataCb.uType, dataCb.rc)); LogFlowFuncLeaveRC(vrc); return vrc; }
/** * Sends a scancode to the keyboard. * * @returns COM status code * @param scancode The scancode to send */ STDMETHODIMP Keyboard::PutScancode(LONG scancode) { com::SafeArray<LONG> scancodes(1); scancodes[0] = scancode; return PutScancodes(ComSafeArrayAsInParam(scancodes), NULL); }
/** * Create a sample VM * * @param virtualBox VirtualBox instance object. */ void createVM(IVirtualBox *virtualBox) { nsresult rc; /* * First create a unnamed new VM. It will be unconfigured and not be saved * in the configuration until we explicitely choose to do so. */ nsCOMPtr<IMachine> machine; rc = virtualBox->CreateMachine(NULL, /* settings file */ NS_LITERAL_STRING("A brand new name").get(), 0, nsnull, /* groups (safearray)*/ nsnull, /* ostype */ nsnull, /* create flags */ getter_AddRefs(machine)); if (NS_FAILED(rc)) { printf("Error: could not create machine! rc=%08X\n", rc); return; } /* * Set some properties */ /* alternative to illustrate the use of string classes */ rc = machine->SetName(NS_ConvertUTF8toUTF16("A new name").get()); rc = machine->SetMemorySize(128); /* * Now a more advanced property -- the guest OS type. This is * an object by itself which has to be found first. Note that we * use the ID of the guest OS type here which is an internal * representation (you can find that by configuring the OS type of * a machine in the GUI and then looking at the <Guest ostype=""/> * setting in the XML file. It is also possible to get the OS type from * its description (win2k would be "Windows 2000") by getting the * guest OS type collection and enumerating it. */ nsCOMPtr<IGuestOSType> osType; rc = virtualBox->GetGuestOSType(NS_LITERAL_STRING("win2k").get(), getter_AddRefs(osType)); if (NS_FAILED(rc)) { printf("Error: could not find guest OS type! rc=%08X\n", rc); } else { machine->SetOSTypeId (NS_LITERAL_STRING("win2k").get()); } /* * Register the VM. Note that this call also saves the VM config * to disk. It is also possible to save the VM settings but not * register the VM. * * Also note that due to current VirtualBox limitations, the machine * must be registered *before* we can attach hard disks to it. */ rc = virtualBox->RegisterMachine(machine); if (NS_FAILED(rc)) { printf("Error: could not register machine! rc=%08X\n", rc); printErrorInfo(); return; } /* * In order to manipulate the registered machine, we must open a session * for that machine. Do it now. */ nsCOMPtr<ISession> session; { nsCOMPtr<nsIComponentManager> manager; rc = NS_GetComponentManager (getter_AddRefs (manager)); if (NS_FAILED(rc)) { printf("Error: could not get component manager! rc=%08X\n", rc); return; } rc = manager->CreateInstanceByContractID (NS_SESSION_CONTRACTID, nsnull, NS_GET_IID(ISession), getter_AddRefs(session)); if (NS_FAILED(rc)) { printf("Error, could not instantiate session object! rc=0x%x\n", rc); return; } rc = machine->LockMachine(session, LockType_Write); if (NS_FAILED(rc)) { printf("Error, could not lock the machine for the session! rc=0x%x\n", rc); return; } /* * After the machine is registered, the initial machine object becomes * immutable. In order to get a mutable machine object, we must query * it from the opened session object. */ rc = session->GetMachine(getter_AddRefs(machine)); if (NS_FAILED(rc)) { printf("Error, could not get machine session! rc=0x%x\n", rc); return; } } /* * Create a virtual harddisk */ nsCOMPtr<IMedium> hardDisk = 0; rc = virtualBox->CreateHardDisk(NS_LITERAL_STRING("VDI").get(), NS_LITERAL_STRING("TestHardDisk.vdi").get(), getter_AddRefs(hardDisk)); if (NS_FAILED(rc)) { printf("Failed creating a hard disk object! rc=%08X\n", rc); } else { /* * We have only created an object so far. No on disk representation exists * because none of its properties has been set so far. Let's continue creating * a dynamically expanding image. */ nsCOMPtr <IProgress> progress; com::SafeArray<MediumVariant_T> mediumVariant(sizeof(MediumVariant_T)*8); mediumVariant.push_back(MediumVariant_Standard); rc = hardDisk->CreateBaseStorage(100, // size in megabytes ComSafeArrayAsInParam(mediumVariant), getter_AddRefs(progress)); // optional progress object if (NS_FAILED(rc)) { printf("Failed creating hard disk image! rc=%08X\n", rc); } else { /* * Creating the image is done in the background because it can take quite * some time (at least fixed size images). We have to wait for its completion. * Here we wait forever (timeout -1) which is potentially dangerous. */ rc = progress->WaitForCompletion(-1); PRInt32 resultCode; progress->GetResultCode(&resultCode); if (NS_FAILED(rc) || NS_FAILED(resultCode)) { printf("Error: could not create hard disk! rc=%08X\n", NS_FAILED(rc) ? rc : resultCode); } else { /* * Now that it's created, we can assign it to the VM. */ rc = machine->AttachDevice(NS_LITERAL_STRING("IDE Controller").get(), // controller identifier 0, // channel number on the controller 0, // device number on the controller DeviceType_HardDisk, hardDisk); if (NS_FAILED(rc)) { printf("Error: could not attach hard disk! rc=%08X\n", rc); } } } } /* * It's got a hard disk but that one is new and thus not bootable. Make it * boot from an ISO file. This requires some processing. First the ISO file * has to be registered and then mounted to the VM's DVD drive and selected * as the boot device. */ nsCOMPtr<IMedium> dvdImage; rc = virtualBox->OpenMedium(NS_LITERAL_STRING("/home/vbox/isos/winnt4ger.iso").get(), DeviceType_DVD, AccessMode_ReadOnly, false /* fForceNewUuid */, getter_AddRefs(dvdImage)); if (NS_FAILED(rc)) printf("Error: could not open CD image! rc=%08X\n", rc); else { /* * Now assign it to our VM */ rc = machine->MountMedium(NS_LITERAL_STRING("IDE Controller").get(), // controller identifier 2, // channel number on the controller 0, // device number on the controller dvdImage, PR_FALSE); // aForce if (NS_FAILED(rc)) { printf("Error: could not mount ISO image! rc=%08X\n", rc); } else { /* * Last step: tell the VM to boot from the CD. */ rc = machine->SetBootOrder (1, DeviceType::DVD); if (NS_FAILED(rc)) { printf("Could not set boot device! rc=%08X\n", rc); } } } /* * Save all changes we've just made. */ rc = machine->SaveSettings(); if (NS_FAILED(rc)) { printf("Could not save machine settings! rc=%08X\n", rc); } /* * It is always important to close the open session when it becomes not * necessary any more. */ session->UnlockMachine(); }
HRESULT Guest::taskCopyFileFromGuest(GuestTask *aTask) { LogFlowFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* * Do *not* take a write lock here since we don't (and won't) * touch any class-specific data (of IGuest) here - only the member functions * which get called here can do that. */ HRESULT rc = S_OK; try { ComObjPtr<Guest> pGuest = aTask->pGuest; /* Does our source file exist? */ BOOL fFileExists; rc = pGuest->FileExists(Bstr(aTask->strSource).raw(), Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), &fFileExists); if (SUCCEEDED(rc)) { if (!fFileExists) rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Source file \"%s\" does not exist, or is not a file"), aTask->strSource.c_str()); } else rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); /* Query file size to make an estimate for our progress object. */ if (SUCCEEDED(rc)) { LONG64 lFileSize; rc = pGuest->FileQuerySize(Bstr(aTask->strSource).raw(), Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), &lFileSize); if (FAILED(rc)) rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); com::SafeArray<IN_BSTR> args; com::SafeArray<IN_BSTR> env; if (SUCCEEDED(rc)) { /* * Prepare tool command line. */ char szSource[RTPATH_MAX]; if (RTStrPrintf(szSource, sizeof(szSource), "%s", aTask->strSource.c_str()) <= sizeof(szSource) - 1) { /* * Normalize path slashes, based on the detected guest. */ Utf8Str osType = mData.mOSTypeId; if ( osType.contains("Microsoft", Utf8Str::CaseInsensitive) || osType.contains("Windows", Utf8Str::CaseInsensitive)) { /* We have a Windows guest. */ RTPathChangeToDosSlashes(szSource, true /* Force conversion. */); } else /* ... or something which isn't from Redmond ... */ { RTPathChangeToUnixSlashes(szSource, true /* Force conversion. */); } args.push_back(Bstr(szSource).raw()); /* Tell our cat tool which file to output. */ } else rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Error preparing command line")); } ComPtr<IProgress> execProgress; ULONG uPID; if (SUCCEEDED(rc)) { LogRel(("Copying file \"%s\" to host \"%s\" (%u bytes) ...\n", aTask->strSource.c_str(), aTask->strDest.c_str(), lFileSize)); /* * Okay, since we gathered all stuff we need until now to start the * actual copying, start the guest part now. */ rc = pGuest->executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_CAT).raw(), Bstr("Copying file to host").raw(), ComSafeArrayAsInParam(args), ComSafeArrayAsInParam(env), Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), ExecuteProcessFlag_WaitForProcessStartOnly | ExecuteProcessFlag_WaitForStdOut, NULL, NULL, execProgress.asOutParam(), &uPID); if (FAILED(rc)) rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } if (SUCCEEDED(rc)) { BOOL fCompleted = FALSE; BOOL fCanceled = FALSE; RTFILE hFileDest; int vrc = RTFileOpen(&hFileDest, aTask->strDest.c_str(), RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); if (RT_FAILURE(vrc)) rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Unable to create/open destination file \"%s\", rc=%Rrc"), aTask->strDest.c_str(), vrc); else { size_t cbToRead = lFileSize; size_t cbTransfered = 0; while ( SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))) && !fCompleted) { SafeArray<BYTE> aOutputData; rc = pGuest->GetProcessOutput(uPID, ProcessOutputFlag_None /* StdOut */, 0 /* No timeout. */, _64K, ComSafeArrayAsOutParam(aOutputData)); if (SUCCEEDED(rc)) { if (aOutputData.size()) { vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"), aTask->strSource.c_str(), cbToRead, vrc); break; } Assert(cbToRead >= aOutputData.size()); cbToRead -= aOutputData.size(); cbTransfered += aOutputData.size(); aTask->pProgress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0)); } /* Nothing read this time; try next round. */ } else { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); break; } } RTFileClose(hFileDest); if (SUCCEEDED(rc)) { if ( cbTransfered && (cbTransfered != lFileSize)) { /* * Only bitch about an unexpected end of a file when there already * was data read from that file. If this was the very first read we can * be (almost) sure that this file is not meant to be read by the specified user. */ rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Unexpected end of file \"%s\" (%u bytes total, %u bytes transferred)"), aTask->strSource.c_str(), lFileSize, cbTransfered); } if (SUCCEEDED(rc)) aTask->pProgress->notifyComplete(S_OK); } } } } } catch (HRESULT aRC) { rc = aRC; } /* Clean up */ aTask->rc = rc; LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); return VINF_SUCCESS; }
HRESULT Guest::taskUpdateGuestAdditions(GuestTask *aTask) { LogFlowFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* * Do *not* take a write lock here since we don't (and won't) * touch any class-specific data (of IGuest) here - only the member functions * which get called here can do that. */ HRESULT rc = S_OK; BOOL fCompleted; BOOL fCanceled; try { ComObjPtr<Guest> pGuest = aTask->pGuest; aTask->pProgress->SetCurrentOperationProgress(10); /* * Determine guest OS type and the required installer image. * At the moment only Windows guests are supported. */ Utf8Str installerImage; Bstr osTypeId; if ( SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam()))) && !osTypeId.isEmpty()) { Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */ if ( osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive) || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive)) { if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive)) installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE"; else installerImage = "VBOXWINDOWSADDITIONS_X86.EXE"; /* Since the installers are located in the root directory, * no further path processing needs to be done (yet). */ } else /* Everything else is not supported (yet). */ throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"), osTypeIdUtf8.c_str()); } else throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Could not detected guest OS type/version, please update manually")); Assert(!installerImage.isEmpty()); /* * Try to open the .ISO file and locate the specified installer. */ RTISOFSFILE iso; int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str()); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->pProgress, Guest::tr("Invalid installation medium detected: \"%s\""), aTask->strSource.c_str()); } else { uint32_t cbOffset; size_t cbLength; vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength); if ( RT_SUCCESS(vrc) && cbOffset && cbLength) { vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(vrc)) rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"), aTask->strSource.c_str(), vrc); } else { switch (vrc) { case VERR_FILE_NOT_FOUND: rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Setup file was not found on installation medium \"%s\""), aTask->strSource.c_str()); break; default: rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""), vrc, aTask->strSource.c_str()); break; } } /* Specify the ouput path on the guest side. */ Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe"; if (RT_SUCCESS(vrc)) { /* Okay, we're ready to start our copy routine on the guest! */ aTask->pProgress->SetCurrentOperationProgress(15); /* Prepare command line args. */ com::SafeArray<IN_BSTR> args; com::SafeArray<IN_BSTR> env; args.push_back(Bstr("--output").raw()); /* We want to write a file ... */ args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */ if (SUCCEEDED(rc)) { ComPtr<IProgress> progressCat; ULONG uPID; /* * Start built-in "vbox_cat" tool (inside VBoxService) to * copy over/pipe the data into a file on the guest (with * system rights, no username/password specified). */ rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(), ExecuteProcessFlag_Hidden | ExecuteProcessFlag_WaitForProcessStartOnly, ComSafeArrayAsInParam(args), ComSafeArrayAsInParam(env), Bstr("").raw() /* Username. */, Bstr("").raw() /* Password */, 5 * 1000 /* Wait 5s for getting the process started. */, &uPID, progressCat.asOutParam(), &vrc); if (FAILED(rc)) { /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller * to silently fall back to "normal" (old) .ISO mounting. */ /* Due to a very limited COM error range we use vrc for a more detailed error * lookup to figure out what went wrong. */ switch (vrc) { /* Guest execution service is not (yet) ready. This basically means that either VBoxService * is not running (yet) or that the Guest Additions are too old (because VBoxService does not * support the guest execution feature in this version). */ case VERR_NOT_FOUND: LogRel(("Guest Additions seem not to be installed yet\n")); rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Guest Additions seem not to be installed or are not ready to update yet")); break; /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */ case VERR_INVALID_PARAMETER: LogRel(("Guest Additions are installed but don't supported automatic updating\n")); rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Installed Guest Additions do not support automatic updating")); break; case VERR_TIMEOUT: LogRel(("Guest was unable to start copying the Guest Additions setup within time\n")); rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress, Guest::tr("Guest was unable to start copying the Guest Additions setup within time")); break; default: rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress, Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"), strInstallerPath.c_str(), vrc); break; } } else { LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str())); LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n", installerImage.c_str(), strInstallerPath.c_str())); aTask->pProgress->SetCurrentOperationProgress(20); /* Wait for process to exit ... */ SafeArray<BYTE> aInputData(_64K); while ( SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted))) && !fCompleted) { size_t cbRead; /* cbLength contains remaining bytes of our installer file * opened above to read. */ size_t cbToRead = RT_MIN(cbLength, _64K); if (cbToRead) { vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead); if ( cbRead && RT_SUCCESS(vrc)) { /* Resize buffer to reflect amount we just have read. */ if (cbRead > 0) aInputData.resize(cbRead); /* Did we reach the end of the content we want to transfer (last chunk)? */ ULONG uFlags = ProcessInputFlag_None; if ( (cbRead < _64K) /* Did we reach the last block which is exactly _64K? */ || (cbToRead - cbRead == 0) /* ... or does the user want to cancel? */ || ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) ) { uFlags |= ProcessInputFlag_EndOfFile; } /* Transfer the current chunk ... */ #ifdef DEBUG_andy LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength)); #endif ULONG uBytesWritten; rc = pGuest->SetProcessInput(uPID, uFlags, 10 * 1000 /* Wait 10s for getting the input data transfered. */, ComSafeArrayAsInParam(aInputData), &uBytesWritten); if (FAILED(rc)) { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); break; } /* If task was canceled above also cancel the process execution. */ if (fCanceled) progressCat->Cancel(); #ifdef DEBUG_andy LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten)); #endif Assert(cbLength >= uBytesWritten); cbLength -= uBytesWritten; } else if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"), installerImage.c_str(), cbToRead, cbLength, vrc); } } /* Internal progress canceled? */ if ( SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled))) && fCanceled) { aTask->pProgress->Cancel(); break; } } } } } RTIsoFsClose(&iso); if ( SUCCEEDED(rc) && ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && !fCanceled ) ) { /* * Installer was transferred successfully, so let's start it * (with system rights). */ LogRel(("Preparing to execute Guest Additions update ...\n")); aTask->pProgress->SetCurrentOperationProgress(66); /* Prepare command line args for installer. */ com::SafeArray<IN_BSTR> installerArgs; com::SafeArray<IN_BSTR> installerEnv; /** @todo Only Windows! */ installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */ /* Note that starting at Windows Vista the lovely session 0 separation applies: * This means that if we run an application with the profile/security context * of VBoxService (system rights!) we're not able to show any UI. */ installerArgs.push_back(Bstr("/S").raw()); /* We want to install in silent mode. */ installerArgs.push_back(Bstr("/l").raw()); /* ... and logging enabled. */ /* Don't quit VBoxService during upgrade because it still is used for this * piece of code we're in right now (that is, here!) ... */ installerArgs.push_back(Bstr("/no_vboxservice_exit").raw()); /* Tell the installer to report its current installation status * using a running VBoxTray instance via balloon messages in the * Windows taskbar. */ installerArgs.push_back(Bstr("/post_installstatus").raw()); /* * Start the just copied over installer with system rights * in silent mode on the guest. Don't use the hidden flag since there * may be pop ups the user has to process. */ ComPtr<IProgress> progressInstaller; ULONG uPID; rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(), ExecuteProcessFlag_WaitForProcessStartOnly, ComSafeArrayAsInParam(installerArgs), ComSafeArrayAsInParam(installerEnv), Bstr("").raw() /* Username */, Bstr("").raw() /* Password */, 10 * 1000 /* Wait 10s for getting the process started */, &uPID, progressInstaller.asOutParam(), &vrc); if (SUCCEEDED(rc)) { LogRel(("Guest Additions update is running ...\n")); /* If the caller does not want to wait for out guest update process to end, * complete the progress object now so that the caller can do other work. */ if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly) aTask->pProgress->notifyComplete(S_OK); else aTask->pProgress->SetCurrentOperationProgress(70); /* Wait until the Guest Additions installer finishes ... */ while ( SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted))) && !fCompleted) { if ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) { progressInstaller->Cancel(); break; } /* Progress canceled by Main API? */ if ( SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled))) && fCanceled) { break; } RTThreadSleep(100); } ExecuteProcessStatus_T retStatus; ULONG uRetExitCode, uRetFlags; rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus); if (SUCCEEDED(rc)) { if (fCompleted) { if (uRetExitCode == 0) { LogRel(("Guest Additions update successful!\n")); if ( SUCCEEDED(aTask->pProgress->COMGETTER(Completed(&fCompleted))) && !fCompleted) aTask->pProgress->notifyComplete(S_OK); } else { LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n", uRetExitCode, retStatus, uRetFlags)); rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"), uRetExitCode, retStatus, uRetFlags); } } else if ( SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled))) && fCanceled) { LogRel(("Guest Additions update was canceled\n")); rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"), uRetExitCode, retStatus, uRetFlags); } else { LogRel(("Guest Additions update was canceled by the user\n")); } } else rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } else rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } } } catch (HRESULT aRC) { rc = aRC; } /* Clean up */ aTask->rc = rc; LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); return VINF_SUCCESS; }
HRESULT Guest::taskCopyFileToGuest(GuestTask *aTask) { LogFlowFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* * Do *not* take a write lock here since we don't (and won't) * touch any class-specific data (of IGuest) here - only the member functions * which get called here can do that. */ HRESULT rc = S_OK; try { ComObjPtr<Guest> pGuest = aTask->pGuest; /* Does our source file exist? */ if (!RTFileExists(aTask->strSource.c_str())) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Source file \"%s\" does not exist, or is not a file"), aTask->strSource.c_str()); } else { RTFILE fileSource; int vrc = RTFileOpen(&fileSource, aTask->strSource.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not open source file \"%s\" for reading (%Rrc)"), aTask->strSource.c_str(), vrc); } else { uint64_t cbSize; vrc = RTFileGetSize(fileSource, &cbSize); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not query file size of \"%s\" (%Rrc)"), aTask->strSource.c_str(), vrc); } else { com::SafeArray<IN_BSTR> args; com::SafeArray<IN_BSTR> env; /* * Prepare tool command line. */ char szOutput[RTPATH_MAX]; if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1) { /* * Normalize path slashes, based on the detected guest. */ Utf8Str osType = mData.mOSTypeId; if ( osType.contains("Microsoft", Utf8Str::CaseInsensitive) || osType.contains("Windows", Utf8Str::CaseInsensitive)) { /* We have a Windows guest. */ RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */); } else /* ... or something which isn't from Redmond ... */ { RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */); } args.push_back(Bstr(szOutput).raw()); /* We want to write a file ... */ } else { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Error preparing command line")); } ComPtr<IProgress> execProgress; ULONG uPID; if (SUCCEEDED(rc)) { LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n", aTask->strSource.c_str(), aTask->strDest.c_str(), cbSize)); /* * Okay, since we gathered all stuff we need until now to start the * actual copying, start the guest part now. */ rc = pGuest->executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_CAT).raw(), Bstr("Copying file to guest").raw(), ComSafeArrayAsInParam(args), ComSafeArrayAsInParam(env), Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), ExecuteProcessFlag_WaitForProcessStartOnly, NULL, NULL, execProgress.asOutParam(), &uPID); if (FAILED(rc)) rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } if (SUCCEEDED(rc)) { BOOL fCompleted = FALSE; BOOL fCanceled = FALSE; uint64_t cbTransferedTotal = 0; SafeArray<BYTE> aInputData(_64K); while ( SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))) && !fCompleted) { size_t cbToRead = cbSize; size_t cbRead = 0; if (cbSize) /* If we have nothing to read, take a shortcut. */ { /** @todo Not very efficient, but works for now. */ vrc = RTFileSeek(fileSource, cbTransferedTotal, RTFILE_SEEK_BEGIN, NULL /* poffActual */); if (RT_SUCCESS(vrc)) { vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(), RT_MIN(cbToRead, _64K), &cbRead); /* * Some other error occured? There might be a chance that RTFileRead * could not resolve/map the native error code to an IPRT code, so just * print a generic error. */ if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not read from file \"%s\" (%Rrc)"), aTask->strSource.c_str(), vrc); break; } } else { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Seeking file \"%s\" failed; offset = %RU64 (%Rrc)"), aTask->strSource.c_str(), cbTransferedTotal, vrc); break; } } /* Resize buffer to reflect amount we just have read. * Size 0 is allowed! */ aInputData.resize(cbRead); ULONG uFlags = ProcessInputFlag_None; /* Did we reach the end of the content we want to transfer (last chunk)? */ if ( (cbRead < _64K) /* Did we reach the last block which is exactly _64K? */ || (cbToRead - cbRead == 0) /* ... or does the user want to cancel? */ || ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) ) { uFlags |= ProcessInputFlag_EndOfFile; } ULONG uBytesWritten = 0; rc = pGuest->SetProcessInput(uPID, uFlags, 0 /* Infinite timeout */, ComSafeArrayAsInParam(aInputData), &uBytesWritten); if (FAILED(rc)) { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); break; } Assert(cbRead <= cbToRead); Assert(cbToRead >= cbRead); cbToRead -= cbRead; cbTransferedTotal += uBytesWritten; Assert(cbTransferedTotal <= cbSize); aTask->pProgress->SetCurrentOperationProgress(cbTransferedTotal / (cbSize / 100.0)); /* End of file reached? */ if (cbToRead == 0) break; /* Did the user cancel the operation above? */ if (fCanceled) break; /* Progress canceled by Main API? */ if ( SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Copy operation of file \"%s\" was canceled on guest side"), aTask->strSource.c_str()); break; } } if (SUCCEEDED(rc)) { /* * If we got here this means the started process either was completed, * canceled or we simply got all stuff transferred. */ ExecuteProcessStatus_T retStatus; ULONG uRetExitCode; rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */, &retStatus, &uRetExitCode); if (FAILED(rc)) { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } else { if ( uRetExitCode != 0 || retStatus != ExecuteProcessStatus_TerminatedNormally) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""), uRetExitCode, retStatus, aTask->strSource.c_str(), aTask->strDest.c_str()); } } } if (SUCCEEDED(rc)) { if (fCanceled) { /* * In order to make the progress object to behave nicely, we also have to * notify the object with a complete event when it's canceled. */ aTask->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest), Guest::getStaticComponentName(), Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str()); } else { /* * Even if we succeeded until here make sure to check whether we really transfered * everything. */ if ( cbSize > 0 && cbTransferedTotal == 0) { /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write * to the destination -> access denied. */ rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Access denied when copying file \"%s\" to \"%s\""), aTask->strSource.c_str(), aTask->strDest.c_str()); } else if (cbTransferedTotal < cbSize) { /* If we did not copy all let the user know. */ rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"), aTask->strSource.c_str(), cbTransferedTotal, cbSize); } else /* Yay, all went fine! */ aTask->pProgress->notifyComplete(S_OK); } } } } RTFileClose(fileSource); } } } catch (HRESULT aRC) { rc = aRC; } /* Clean up */ aTask->rc = rc; LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); return VINF_SUCCESS; }
STDMETHODIMP GuestEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent) { switch (aType) { case VBoxEventType_OnGuestSessionRegistered: { HRESULT rc; do { ComPtr<IGuestSessionRegisteredEvent> pEvent = aEvent; Assert(!pEvent.isNull()); ComPtr<IGuestSession> pSession; CHECK_ERROR_BREAK(pEvent, COMGETTER(Session)(pSession.asOutParam())); AssertBreak(!pSession.isNull()); BOOL fRegistered; CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered)); Bstr strName; CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam())); ULONG uID; CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID)); RTPrintf("Session ID=%RU32 \"%s\" %s\n", uID, Utf8Str(strName).c_str(), fRegistered ? "registered" : "unregistered"); if (fRegistered) { if (mfVerbose) RTPrintf("Registering ...\n"); /* Register for IGuestSession events. */ ComObjPtr<GuestSessionEventListenerImpl> pListener; pListener.createObject(); CHECK_ERROR_BREAK(pListener, init(new GuestSessionEventListener())); ComPtr<IEventSource> es; CHECK_ERROR_BREAK(pSession, COMGETTER(EventSource)(es.asOutParam())); com::SafeArray<VBoxEventType_T> eventTypes; eventTypes.push_back(VBoxEventType_OnGuestFileRegistered); eventTypes.push_back(VBoxEventType_OnGuestProcessRegistered); CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), true /* Active listener */)); GuestSessionStats sessionStats(pListener); mSessions[pSession] = sessionStats; } else { GuestEventSessions::iterator itSession = mSessions.find(pSession); if (itSession != mSessions.end()) { if (mfVerbose) RTPrintf("Unregistering ...\n"); if (!itSession->first.isNull()) { /* Listener unregistration. */ ComPtr<IEventSource> pES; CHECK_ERROR_BREAK(itSession->first, COMGETTER(EventSource)(pES.asOutParam())); if (!pES.isNull()) CHECK_ERROR_BREAK(pES, UnregisterListener(itSession->second.mListener)); itSession->first->Release(); } mSessions.erase(itSession); } } } while (0); break; } default: AssertFailed(); } return S_OK; }
STDMETHODIMP GuestSessionEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent) { switch (aType) { case VBoxEventType_OnGuestFileRegistered: { HRESULT rc; do { ComPtr<IGuestFileRegisteredEvent> pEvent = aEvent; Assert(!pEvent.isNull()); ComPtr<IGuestFile> pFile; CHECK_ERROR_BREAK(pEvent, COMGETTER(File)(pFile.asOutParam())); AssertBreak(!pFile.isNull()); BOOL fRegistered; CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered)); Bstr strPath; CHECK_ERROR_BREAK(pFile, COMGETTER(FileName)(strPath.asOutParam())); RTPrintf("File \"%s\" %s\n", Utf8Str(strPath).c_str(), fRegistered ? "registered" : "unregistered"); if (fRegistered) { if (mfVerbose) RTPrintf("Registering ...\n"); /* Register for IGuestFile events. */ ComObjPtr<GuestFileEventListenerImpl> pListener; pListener.createObject(); CHECK_ERROR_BREAK(pListener, init(new GuestFileEventListener())); ComPtr<IEventSource> es; CHECK_ERROR_BREAK(pFile, COMGETTER(EventSource)(es.asOutParam())); com::SafeArray<VBoxEventType_T> eventTypes; eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), true /* Active listener */)); GuestFileStats fileStats(pListener); mFiles[pFile] = fileStats; } else { GuestEventFiles::iterator itFile = mFiles.find(pFile); if (itFile != mFiles.end()) { if (mfVerbose) RTPrintf("Unregistering file ...\n"); if (!itFile->first.isNull()) { /* Listener unregistration. */ ComPtr<IEventSource> pES; CHECK_ERROR(itFile->first, COMGETTER(EventSource)(pES.asOutParam())); if (!pES.isNull()) CHECK_ERROR(pES, UnregisterListener(itFile->second.mListener)); itFile->first->Release(); } mFiles.erase(itFile); } } } while (0); break; } case VBoxEventType_OnGuestProcessRegistered: { HRESULT rc; do { ComPtr<IGuestProcessRegisteredEvent> pEvent = aEvent; Assert(!pEvent.isNull()); ComPtr<IGuestProcess> pProcess; CHECK_ERROR_BREAK(pEvent, COMGETTER(Process)(pProcess.asOutParam())); AssertBreak(!pProcess.isNull()); BOOL fRegistered; CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered)); Bstr strPath; CHECK_ERROR_BREAK(pProcess, COMGETTER(ExecutablePath)(strPath.asOutParam())); RTPrintf("Process \"%s\" %s\n", Utf8Str(strPath).c_str(), fRegistered ? "registered" : "unregistered"); if (fRegistered) { if (mfVerbose) RTPrintf("Registering ...\n"); /* Register for IGuestProcess events. */ ComObjPtr<GuestProcessEventListenerImpl> pListener; pListener.createObject(); CHECK_ERROR_BREAK(pListener, init(new GuestProcessEventListener())); ComPtr<IEventSource> es; CHECK_ERROR_BREAK(pProcess, COMGETTER(EventSource)(es.asOutParam())); com::SafeArray<VBoxEventType_T> eventTypes; eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), true /* Active listener */)); GuestProcStats procStats(pListener); mProcs[pProcess] = procStats; } else { GuestEventProcs::iterator itProc = mProcs.find(pProcess); if (itProc != mProcs.end()) { if (mfVerbose) RTPrintf("Unregistering process ...\n"); if (!itProc->first.isNull()) { /* Listener unregistration. */ ComPtr<IEventSource> pES; CHECK_ERROR(itProc->first, COMGETTER(EventSource)(pES.asOutParam())); if (!pES.isNull()) CHECK_ERROR(pES, UnregisterListener(itProc->second.mListener)); itProc->first->Release(); } mProcs.erase(itProc); } } } while (0); break; } case VBoxEventType_OnGuestSessionStateChanged: { HRESULT rc; do { ComPtr<IGuestSessionStateChangedEvent> pEvent = aEvent; Assert(!pEvent.isNull()); ComPtr<IGuestSession> pSession; CHECK_ERROR_BREAK(pEvent, COMGETTER(Session)(pSession.asOutParam())); AssertBreak(!pSession.isNull()); GuestSessionStatus_T sessSts; CHECK_ERROR_BREAK(pSession, COMGETTER(Status)(&sessSts)); ULONG uID; CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID)); Bstr strName; CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam())); RTPrintf("Session ID=%RU32 \"%s\" changed status to [%s]\n", uID, Utf8Str(strName).c_str(), gctlGuestSessionStatusToText(sessSts)); } while (0); break; } default: AssertFailed(); } return S_OK; }
/** * Register passive event listener for the selected VM. * * @param virtualBox ptr to IVirtualBox object * @param session ptr to ISession object * @param id identifies the machine to start */ static void registerPassiveEventListener(IVirtualBox *virtualBox, ISession *session, BSTR machineId) { IConsole *console = NULL; HRESULT rc; rc = ISession_get_Console(session, &console); if ((SUCCEEDED(rc)) && console) { IEventSource *es = NULL; rc = IConsole_get_EventSource(console, &es); if (SUCCEEDED(rc) && es) { static const ULONG interestingEvents[] = { VBoxEventType_OnMousePointerShapeChanged, VBoxEventType_OnMouseCapabilityChanged, VBoxEventType_OnKeyboardLedsChanged, VBoxEventType_OnStateChanged, VBoxEventType_OnAdditionsStateChanged, VBoxEventType_OnNetworkAdapterChanged, VBoxEventType_OnSerialPortChanged, VBoxEventType_OnParallelPortChanged, VBoxEventType_OnStorageControllerChanged, VBoxEventType_OnMediumChanged, VBoxEventType_OnVRDEServerChanged, VBoxEventType_OnUSBControllerChanged, VBoxEventType_OnUSBDeviceStateChanged, VBoxEventType_OnSharedFolderChanged, VBoxEventType_OnRuntimeError, VBoxEventType_OnCanShowWindow, VBoxEventType_OnShowWindow }; SAFEARRAY *interestingEventsSA = NULL; IEventListener *consoleListener = NULL; /* The VirtualBox API expects enum values as VT_I4, which in the * future can be hopefully relaxed. */ interestingEventsSA = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, sizeof(interestingEvents) / sizeof(interestingEvents[0])); g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(interestingEventsSA, &interestingEvents, sizeof(interestingEvents)); rc = IEventSource_CreateListener(es, &consoleListener); if (SUCCEEDED(rc) && consoleListener) { rc = IEventSource_RegisterListener(es, consoleListener, ComSafeArrayAsInParam(interestingEventsSA), 0 /* passive */); if (SUCCEEDED(rc)) { /* Just wait here for events, no easy way to do this better * as there's not much to do after this completes. */ printf("Entering event loop, PowerOff the machine to exit or press Ctrl-C to terminate\n"); fflush(stdout); #ifdef WIN32 SetConsoleCtrlHandler(ctrlCHandler, TRUE); #else signal(SIGINT, (void (*)(int))ctrlCHandler); #endif while (!g_fStop) { IEvent *ev = NULL; rc = IEventSource_GetEvent(es, consoleListener, 250, &ev); if (FAILED(rc)) { printf("Failed getting event: %#x\n", rc); g_fStop = 1; continue; } /* handle timeouts, resulting in NULL events */ if (!ev) continue; rc = EventListenerDemoProcessEvent(ev); if (FAILED(rc)) { printf("Failed processing event: %#x\n", rc); g_fStop = 1; /* finish processing the event */ } rc = IEventSource_EventProcessed(es, consoleListener, ev); if (FAILED(rc)) { printf("Failed to mark event as processed: %#x\n", rc); g_fStop = 1; /* continue with event release */ } if (ev) { IEvent_Release(ev); ev = NULL; } } #ifdef WIN32 SetConsoleCtrlHandler(ctrlCHandler, FALSE); #else signal(SIGINT, SIG_DFL); #endif } else { printf("Failed to register event listener.\n"); } IEventSource_UnregisterListener(es, (IEventListener *)consoleListener); IEventListener_Release(consoleListener); } else { printf("Failed to create an event listener instance.\n"); } g_pVBoxFuncs->pfnSafeArrayDestroy(interestingEventsSA); IEventSource_Release(es); } else { printf("Failed to get the event source instance.\n"); } IConsole_Release(console); } }
/** * Handles the setregisters sub-command. * * @returns Suitable exit code. * @param pArgs The handler arguments. * @param pDebugger Pointer to the debugger interface. */ static RTEXITCODE handleDebugVM_SetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger) { /* * We take a list of register assignments, that is register=value. */ ULONG idCpu = 0; com::SafeArray<IN_BSTR> aBstrNames; com::SafeArray<IN_BSTR> aBstrValues; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; static const RTGETOPTDEF s_aOptions[] = { { "--cpu", 'c', RTGETOPT_REQ_UINT32 }, }; int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); AssertRCReturn(rc, RTEXITCODE_FAILURE); while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (rc) { case 'c': idCpu = ValueUnion.u32; break; case VINF_GETOPT_NOT_OPTION: { const char *pszEqual = strchr(ValueUnion.psz, '='); if (!pszEqual) return errorSyntax("setregisters expects input on the form 'register=value' got '%s'", ValueUnion.psz); try { com::Bstr bstrName(ValueUnion.psz, pszEqual - ValueUnion.psz); com::Bstr bstrValue(pszEqual + 1); if ( !aBstrNames.push_back(bstrName.raw()) || !aBstrValues.push_back(bstrValue.raw())) throw std::bad_alloc(); } catch (std::bad_alloc) { RTMsgError("Out of memory\n"); return RTEXITCODE_FAILURE; } break; } default: return errorGetOpt(rc, &ValueUnion); } } if (!aBstrNames.size()) return errorSyntax("The setregisters sub-command takes at least one register name"); /* * If it is only one register, use the single register method just so * we expose it and can test it from the command line. */ if (aBstrNames.size() == 1) { CHECK_ERROR2I_RET(pDebugger, SetRegister(idCpu, aBstrNames[0], aBstrValues[0]), RTEXITCODE_FAILURE); RTPrintf("Successfully set %ls\n", aBstrNames[0]); } else { CHECK_ERROR2I_RET(pDebugger, SetRegisters(idCpu, ComSafeArrayAsInParam(aBstrNames), ComSafeArrayAsInParam(aBstrValues)), RTEXITCODE_FAILURE); RTPrintf("Successfully set %u registers\n", aBstrNames.size()); } return RTEXITCODE_SUCCESS; }