/** * Initializes the COM runtime. * * This method must be called on each thread of the client application that * wants to access COM facilities. The initialization must be performed before * calling any other COM method or attempting to instantiate COM objects. * * On platforms using XPCOM, this method uses the following scheme to search for * XPCOM runtime: * * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies * is used to search XPCOM libraries and components. If this method fails to * initialize XPCOM runtime using this path, it will immediately return a * failure and will NOT check for other paths as described below. * * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the * given order: * * a) Compiled-in application data directory (as returned by * RTPathAppPrivateArch()) * b) "/usr/lib/virtualbox" (Linux only) * c) "/opt/VirtualBox" (Linux only) * * The first path for which the initialization succeeds will be used. * * On MS COM platforms, the COM runtime is provided by the system and does not * need to be searched for. * * Once the COM subsystem is no longer necessary on a given thread, Shutdown() * must be called to free resources allocated for it. Note that a thread may * call Initialize() several times but for each of tese calls there must be a * corresponding Shutdown() call. * * @return S_OK on success and a COM result code in case of failure. */ HRESULT Initialize(bool fGui) { HRESULT rc = E_FAIL; #if !defined(VBOX_WITH_XPCOM) /* * We initialize COM in GUI thread in STA, to be compliant with QT and * OLE requirments (for example to allow D&D), while other threads * initialized in regular MTA. To allow fast proxyless access from * GUI thread to COM objects, we explicitly provide our COM objects * with free threaded marshaller. * !!!!! Please think twice before touching this code !!!!! */ DWORD flags = fGui ? COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY : COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY; rc = CoInitializeEx(NULL, flags); /* the overall result must be either S_OK or S_FALSE (S_FALSE means * "already initialized using the same apartment model") */ AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc)); /* To be flow compatible with the XPCOM case, we return here if this isn't * the main thread or if it isn't its first initialization call. * Note! CoInitializeEx and CoUninitialize does it's own reference * counting, so this exercise is entirely for the EventQueue init. */ bool fRc; RTTHREAD hSelf = RTThreadSelf(); if (hSelf != NIL_RTTHREAD) ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc); else fRc = false; if (fGui) Assert(RTThreadIsMain(hSelf)); if (!fRc) { if ( gCOMMainThread == hSelf && SUCCEEDED(rc)) gCOMMainInitCount++; AssertComRC(rc); return rc; } Assert(RTThreadIsMain(hSelf)); /* this is the first main thread initialization */ Assert(gCOMMainInitCount == 0); if (SUCCEEDED(rc)) gCOMMainInitCount = 1; #else /* !defined (VBOX_WITH_XPCOM) */ /* Unused here */ NOREF(fGui); if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true) { /* XPCOM is already initialized on the main thread, no special * initialization is necessary on additional threads. Just increase * the init counter if it's a main thread again (to correctly support * nested calls to Initialize()/Shutdown() for compatibility with * Win32). */ nsCOMPtr<nsIEventQueue> eventQ; rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); if (NS_SUCCEEDED(rc)) { PRBool isOnMainThread = PR_FALSE; rc = eventQ->IsOnCurrentThread(&isOnMainThread); if (NS_SUCCEEDED(rc) && isOnMainThread) ++gXPCOMInitCount; } AssertComRC(rc); return rc; } Assert(RTThreadIsMain(RTThreadSelf())); /* this is the first initialization */ gXPCOMInitCount = 1; bool const fInitEventQueues = true; /* prepare paths for registry files */ char szCompReg[RTPATH_MAX]; char szXptiDat[RTPATH_MAX]; int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg)); AssertRCReturn(vrc, NS_ERROR_FAILURE); strcpy(szXptiDat, szCompReg); vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); LogFlowFunc(("component registry : \"%s\"\n", szCompReg)); LogFlowFunc(("XPTI data file : \"%s\"\n", szXptiDat)); #if defined (XPCOM_GLUE) XPCOMGlueStartup(nsnull); #endif static const char *kAppPathsToProbe[] = { NULL, /* 0: will use VBOX_APP_HOME */ NULL, /* 1: will try RTPathAppPrivateArch() */ #ifdef RT_OS_LINUX "/usr/lib/virtualbox", "/opt/VirtualBox", #elif RT_OS_SOLARIS "/opt/VirtualBox/amd64", "/opt/VirtualBox/i386", #elif RT_OS_DARWIN "/Application/VirtualBox.app/Contents/MacOS", #endif }; /* Find out the directory where VirtualBox binaries are located */ for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i) { char szAppHomeDir[RTPATH_MAX]; if (i == 0) { /* Use VBOX_APP_HOME if present */ vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL); if (vrc == VERR_ENV_VAR_NOT_FOUND) continue; AssertRC(vrc); } else if (i == 1) { /* Use RTPathAppPrivateArch() first */ vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir)); AssertRC(vrc); } else { /* Iterate over all other paths */ szAppHomeDir[RTPATH_MAX - 1] = '\0'; strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1); vrc = VINF_SUCCESS; } if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; continue; } char szCompDir[RTPATH_MAX]; vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components"); if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; continue; } LogFlowFunc(("component directory : \"%s\"\n", szCompDir)); nsCOMPtr<DirectoryServiceProvider> dsProv; dsProv = new DirectoryServiceProvider(); if (dsProv) rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir); else rc = NS_ERROR_OUT_OF_MEMORY; if (NS_FAILED(rc)) break; /* Setup the application path for NS_InitXPCOM2. Note that we properly * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory * service provider but it seems to be activated after the directory * service is used for the first time (see the source NS_InitXPCOM2). So * use the same value here to be on the safe side. */ nsCOMPtr <nsIFile> appDir; { char *appDirCP = NULL; vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir); if (RT_SUCCESS(vrc)) { nsCOMPtr<nsILocalFile> file; rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP), PR_FALSE, getter_AddRefs(file)); if (NS_SUCCEEDED(rc)) appDir = do_QueryInterface(file, &rc); RTStrFree(appDirCP); } else rc = NS_ERROR_FAILURE; } if (NS_FAILED(rc)) break; /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that * still use it instead of the directory service happy */ vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir); AssertRC(vrc); /* Finally, initialize XPCOM */ { nsCOMPtr<nsIServiceManager> serviceManager; rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv); if (NS_SUCCEEDED(rc)) { nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager, &rc); if (NS_SUCCEEDED(rc)) { rc = registrar->AutoRegister(nsnull); if (NS_SUCCEEDED(rc)) { /* We succeeded, stop probing paths */ LogFlowFunc(("Succeeded.\n")); break; } } } } /* clean up before the new try */ rc = NS_ShutdownXPCOM(nsnull); if (i == 0) { /* We failed with VBOX_APP_HOME, don't probe other paths */ break; } } #endif /* !defined (VBOX_WITH_XPCOM) */ // for both COM and XPCOM, we only get here if this is the main thread; // only then initialize the autolock system (AutoLock.cpp) Assert(RTThreadIsMain(RTThreadSelf())); util::InitAutoLockSystem(); AssertComRC(rc); /* * Init the main event queue (ASSUMES it cannot fail). */ if (SUCCEEDED(rc)) EventQueue::init(); return rc; }
DECLCALLBACK(int) VBoxClipboardWorker(void *pInstance, bool volatile *pfShutdown) { AssertPtr(pInstance); LogFlowFunc(("pInstance=%p\n", pInstance)); /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); const PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance; AssertPtr(pCtx); const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win; int rc; /* The thread waits for incoming messages from the host. */ for (;;) { uint32_t u32Msg; uint32_t u32Formats; rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats); if (RT_FAILURE(rc)) { if (rc == VERR_INTERRUPTED) break; LogFunc(("Error getting host message, rc=%Rrc\n", rc)); if (*pfShutdown) break; /* Wait a bit before retrying. */ RTThreadSleep(1000); continue; } else { LogFlowFunc(("u32Msg=%RU32, u32Formats=0x%x\n", u32Msg, u32Formats)); switch (u32Msg) { case VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS: { /* The host has announced available clipboard formats. * Forward the information to the window, so it can later * respond to WM_RENDERFORMAT message. */ ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats); break; } case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA: { /* The host needs data in the specified format. */ ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_READ_DATA, 0, u32Formats); break; } case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT: { /* The host is terminating. */ LogRel(("Clipboard: Terminating ...\n")); ASMAtomicXchgBool(pfShutdown, true); break; } default: { LogFlowFunc(("Unsupported message from host, message=%RU32\n", u32Msg)); /* Wait a bit before retrying. */ RTThreadSleep(1000); break; } } } if (*pfShutdown) break; } LogFlowFuncLeaveRC(rc); return rc; }
/** * Issued by the QDrag object as soon as the current drop action has changed. * * @param dropAction New drop action to use. */ void UIDnDMIMEData::sltDropActionChanged(Qt::DropAction dropAction) { LogFlowFunc(("dropAction=0x%x\n", dropAction)); m_curAction = dropAction; }
/* This function will free m0! */ int ip_output0(PNATState pData, struct socket *so, struct mbuf *m0, int urg) { register struct ip *ip; register struct mbuf *m = m0; register int hlen = sizeof(struct ip); int len, off, error = 0; struct ethhdr *eh = NULL; uint8_t eth_dst[ETH_ALEN]; int rc = 1; STAM_PROFILE_START(&pData->StatIP_output, a); #ifdef LOG_ENABLED LogFlowFunc(("ip_output: so = %R[natsock], m0 = %lx\n", so, (long)m0)); #else NOREF(so); #endif M_ASSERTPKTHDR(m); Assert(m->m_pkthdr.header); #if 0 /* We do no options */ if (opt) { m = ip_insertoptions(m, opt, &len); hlen = len; } #endif ip = mtod(m, struct ip *); LogFunc(("ip(src:%RTnaipv4, dst:%RTnaipv4)\n", ip->ip_src, ip->ip_dst)); /* * Fill in IP header. */ ip->ip_v = IPVERSION; ip->ip_off &= IP_DF; ip->ip_id = RT_H2N_U16(ip_currid++); ip->ip_hl = hlen >> 2; ipstat.ips_localout++; /* Current TCP/IP stack hasn't routing information at * all so we need to calculate destination ethernet address */ rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst); if (RT_FAILURE(rc)) goto exit_drop_package; eh = (struct ethhdr *)(m->m_data - ETH_HLEN); /* * If small enough for interface, can just send directly. */ if ((u_int16_t)ip->ip_len <= if_mtu) { ip->ip_len = RT_H2N_U16((u_int16_t)ip->ip_len); ip->ip_off = RT_H2N_U16((u_int16_t)ip->ip_off); ip->ip_sum = 0; ip->ip_sum = cksum(m, hlen); if (!(m->m_flags & M_SKIP_FIREWALL)){ struct m_tag *t; STAM_PROFILE_START(&pData->StatALIAS_output, b); rc = LibAliasOut(pData->proxy_alias, mtod(m, char *), m_length(m, NULL)); if (rc == PKT_ALIAS_IGNORED) { Log(("NAT: packet was droppped\n")); goto exit_drop_package; } STAM_PROFILE_STOP(&pData->StatALIAS_output, b); } else
/** * Reads a completed/error'd URB from the client driver (no waiting). * * @param pDevSol The Solaris device instance. */ static PVUSBURB usbProxySolarisUrbComplete(PUSBPROXYDEVSOL pDevSol) { LogFlowFunc((USBPROXY ":usbProxySolarisUrbComplete pDevSol=%p\n", pDevSol)); VBOXUSBREQ_URB UrbReq; bzero(&UrbReq, sizeof(UrbReq)); int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_REAP_URB, &UrbReq, sizeof(UrbReq)); if (RT_SUCCESS(rc)) { if (UrbReq.pvUrbR3) { PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)UrbReq.pvUrbR3; PVUSBURB pUrb = pUrbSol->pVUsbUrb; if (RT_LIKELY(pUrb)) { Assert(pUrb->u32Magic == VUSBURB_MAGIC); /* * Update the URB. */ if ( pUrb->enmType == VUSBXFERTYPE_ISOC && pUrb->enmDir == VUSBDIRECTION_IN) { size_t cbData = 0; for (unsigned i = 0; i < UrbReq.cIsocPkts; i++) { pUrb->aIsocPkts[i].cb = UrbReq.aIsocPkts[i].cbActPkt; cbData += UrbReq.aIsocPkts[i].cbActPkt; pUrb->aIsocPkts[i].enmStatus = UrbReq.aIsocPkts[i].enmStatus; } LogFlow((USBPROXY ":usbProxySolarisUrbComplete ISOC cbData=%d cbActPktSum=%d\n", pUrb->cbData, cbData)); pUrb->cbData = cbData; pUrb->enmStatus = UrbReq.enmStatus; } else { pUrb->cbData = UrbReq.cbData; pUrb->enmStatus = UrbReq.enmStatus; } RTCritSectEnter(&pDevSol->CritSect); /* * Remove from the active list. */ if (pUrbSol->pNext) pUrbSol->pNext->pPrev = pUrbSol->pPrev; if (pUrbSol->pPrev) pUrbSol->pPrev->pNext = pUrbSol->pNext; else { Assert(pDevSol->pInFlightHead == pUrbSol); pDevSol->pInFlightHead = pUrbSol->pNext; } /* * Link it into the taxing list. */ pUrbSol->pNext = NULL; pUrbSol->pPrev = pDevSol->pTaxingTail; if (pDevSol->pTaxingTail) pDevSol->pTaxingTail->pNext = pUrbSol; else pDevSol->pTaxingHead = pUrbSol; pDevSol->pTaxingTail = pUrbSol; RTCritSectLeave(&pDevSol->CritSect); LogFlow((USBPROXY "usbProxySolarisUrbComplete: cb=%d EndPt=%#x enmDir=%d enmStatus=%s (%d) \n", pUrb->cbData, pUrb->EndPt, pUrb->enmDir, pUrb->enmStatus == VUSBSTATUS_OK ? "OK" : "** Failed **", pUrb->enmStatus)); // if (pUrb->cbData < 2049) // LogFlow((USBPROXY "%.*Rhxd\n", pUrb->cbData, pUrb->abData)); return pUrb; } } } else { if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED) LogRel((USBPROXY ":Reaping URB failed. rc=%Rrc\n", rc)); } return NULL; }
static void parallelR3IrqClear(PARALLELPORT *pThis) { LogFlowFunc(("%d 0\n", pThis->iIrq)); PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->iIrq, 0); }
static DECLCALLBACK(int) drvscsiReqTransferEnqueue(VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq) { int rc = VINF_SUCCESS; PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser; if (pThis->pDrvBlockAsync) { /* async I/O path. */ VSCSIIOREQTXDIR enmTxDir; LogFlowFunc(("Enqueuing hVScsiIoReq=%#p\n", hVScsiIoReq)); enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq); switch (enmTxDir) { case VSCSIIOREQTXDIR_FLUSH: { rc = pThis->pDrvBlockAsync->pfnStartFlush(pThis->pDrvBlockAsync, hVScsiIoReq); if ( RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS && pThis->cErrors++ < MAX_LOG_REL_ERRORS) LogRel(("SCSI#%u: Flush returned rc=%Rrc\n", pThis->pDrvIns->iInstance, rc)); break; } case VSCSIIOREQTXDIR_UNMAP: { PCRTRANGE paRanges; unsigned cRanges; rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRanges, &cRanges); AssertRC(rc); pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1; rc = pThis->pDrvBlockAsync->pfnStartDiscard(pThis->pDrvBlockAsync, paRanges, cRanges, hVScsiIoReq); if ( RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS && pThis->cErrors++ < MAX_LOG_REL_ERRORS) LogRel(("SCSI#%u: Discard returned rc=%Rrc\n", pThis->pDrvIns->iInstance, rc)); break; } case VSCSIIOREQTXDIR_READ: case VSCSIIOREQTXDIR_WRITE: { uint64_t uOffset = 0; size_t cbTransfer = 0; size_t cbSeg = 0; PCRTSGSEG paSeg = NULL; unsigned cSeg = 0; rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer, &cSeg, &cbSeg, &paSeg); AssertRC(rc); if (enmTxDir == VSCSIIOREQTXDIR_READ) { pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1; rc = pThis->pDrvBlockAsync->pfnStartRead(pThis->pDrvBlockAsync, uOffset, paSeg, cSeg, cbTransfer, hVScsiIoReq); STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbTransfer); } else { pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1; rc = pThis->pDrvBlockAsync->pfnStartWrite(pThis->pDrvBlockAsync, uOffset, paSeg, cSeg, cbTransfer, hVScsiIoReq); STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbTransfer); } if ( RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS && pThis->cErrors++ < MAX_LOG_REL_ERRORS) LogRel(("SCSI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n", pThis->pDrvIns->iInstance, enmTxDir == VSCSIIOREQTXDIR_READ ? "Read" : "Write", uOffset, cbTransfer, rc)); break; } default: AssertMsgFailed(("Invalid transfer direction %u\n", enmTxDir)); } if (rc == VINF_VD_ASYNC_IO_FINISHED) { if (enmTxDir == VSCSIIOREQTXDIR_READ) pThis->pLed->Actual.s.fReading = 0; else if (enmTxDir == VSCSIIOREQTXDIR_WRITE) pThis->pLed->Actual.s.fWriting = 0; else AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir)); VSCSIIoReqCompleted(hVScsiIoReq, VINF_SUCCESS, false); rc = VINF_SUCCESS; } else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) rc = VINF_SUCCESS; else if (RT_FAILURE(rc)) { if (enmTxDir == VSCSIIOREQTXDIR_READ) pThis->pLed->Actual.s.fReading = 0; else if (enmTxDir == VSCSIIOREQTXDIR_WRITE) pThis->pLed->Actual.s.fWriting = 0; else AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir)); VSCSIIoReqCompleted(hVScsiIoReq, rc, drvscsiIsRedoPossible(rc)); rc = VINF_SUCCESS; } else AssertMsgFailed(("Invalid return code rc=%Rrc\n", rc)); } else { /* I/O thread. */ rc = RTReqQueueCallEx(pThis->hQueueRequests, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)drvscsiProcessRequestOne, 2, pThis, hVScsiIoReq); } return rc; }
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; }
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; }
int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) { int rc = VINF_SUCCESS; switch (uMsg) { case DragAndDropSvc::HOST_DND_HG_EVT_ENTER: { clear(); LogFlowFunc(("HOST_DND_HG_EVT_ENTER\n")); DO(("HOST_DND_HG_EVT_ENTER\n")); /* Verify parameter count and types. */ if ( cParms != 7 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */ || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */ || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */ || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */ || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */) rc = VERR_INVALID_PARAMETER; else { m_fOpInProcess = true; DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); m_dndMessageQueue.append(pMessage); } break; } case DragAndDropSvc::HOST_DND_HG_EVT_MOVE: { LogFlowFunc(("HOST_DND_HG_EVT_MOVE\n")); DO(("HOST_DND_HG_EVT_MOVE\n")); /* Verify parameter count and types. */ if ( cParms != 7 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */ || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */ || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */ || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */ || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */) rc = VERR_INVALID_PARAMETER; else { m_fOpInProcess = true; DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); m_dndMessageQueue.append(pMessage); } break; } case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE: { LogFlowFunc(("HOST_DND_HG_EVT_LEAVE\n")); DO(("HOST_DND_HG_EVT_LEAVE\n")); /* Verify parameter count and types. */ if (cParms != 0) rc = VERR_INVALID_PARAMETER; else { DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); m_dndMessageQueue.append(pMessage); } m_fOpInProcess = false; break; } case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED: { LogFlowFunc(("HOST_DND_HG_EVT_DROPPED\n")); DO(("HOST_DND_HG_EVT_DROPPED\n")); /* Verify parameter count and types. */ if ( cParms != 7 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */ || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */ || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */ || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */ || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */) rc = VERR_INVALID_PARAMETER; else { DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); m_dndMessageQueue.append(pMessage); } break; } case DragAndDropSvc::HOST_DND_HG_SND_DATA: { LogFlowFunc(("HOST_DND_HG_SND_DATA\n")); DO(("HOST_DND_HG_SND_DATA\n")); /* Verify parameter count and types. */ if ( cParms != 5 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */ || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* format */ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */ || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /* data */ || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* data size */) rc = VERR_INVALID_PARAMETER; else { DnDHGSendDataMessage *pMessage = new DnDHGSendDataMessage(uMsg, cParms, paParms, m_pfnProgressCallback, m_pvProgressUser); m_dndMessageQueue.append(pMessage); } break; } #ifdef VBOX_WITH_DRAG_AND_DROP_GH case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: { LogFlowFunc(("HOST_DND_GH_REQ_PENDING\n")); DO(("HOST_DND_GH_REQ_PENDING\n")); /* Verify parameter count and types. */ if ( cParms != 1 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */) rc = VERR_INVALID_PARAMETER; else { DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); m_dndMessageQueue.append(pMessage); } break; } case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: { LogFlowFunc(("HOST_DND_GH_EVT_DROPPED\n")); DO(("HOST_DND_GH_EVT_DROPPED\n")); /* Verify parameter count and types. */ if ( cParms != 3 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* action */) rc = VERR_INVALID_PARAMETER; else { DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); m_dndMessageQueue.append(pMessage); } break; } #endif default: rc = VERR_NOT_IMPLEMENTED; break; } return rc; }
/* * Some sort of host operation on an vboxfs_node has failed or it has been * deleted. Mark this node and any children as stale, deleting knowledge * about any which do not have active vnodes or children * This also handle deleting an inactive node that was already stale. */ static void fvsnode_make_stale(struct vboxfs_node *node) { struct vboxfs_node *np; int len; avl_index_t where; /* * First deal with any children of a directory node. * If a directory becomes stale, anything below it becomes stale too. */ if (!node->sf_is_stale && node->sf_type == VDIR) { len = strlen(node->sf_path); np = node; while ((np = AVL_NEXT(&sfnodes, node)) != NULL) { ASSERT(!n->sf_is_stale); /* * quit when no longer seeing children of node */ if (n->sf_sffs != node->sf_sffs || strncmp(node->sf_path, n->sf_path, len) != 0 || n->sf_path[len] != '/') break; /* * Either mark the child as stale or destroy it */ if (n->sf_vnode == NULL && n->sf_children == 0) { sfnode_destroy(n); } else { LogFlowFunc(("sffs_make_stale(%s) sub\n", n->sf_path)); sfnode_clear_dir_list(n); if (avl_find(&sfnodes, n, &where) == NULL) panic("sfnode_make_stale(%s)" " not in sfnodes", n->sf_path); avl_remove(&sfnodes, n); n->sf_is_stale = 1; if (avl_find(&stale_sfnodes, n, &where) != NULL) panic("sffs_make_stale(%s) duplicates", n->sf_path); avl_insert(&stale_sfnodes, n, where); } } } /* * Now deal with the given node. */ if (node->sf_vnode == NULL && node->sf_children == 0) { sfnode_destroy(node); } else if (!node->sf_is_stale) { LogFlowFunc(("sffs_make_stale(%s)\n", node->sf_path)); sfnode_clear_dir_list(node); if (node->sf_parent) sfnode_clear_dir_list(node->sf_parent); if (avl_find(&sfnodes, node, &where) == NULL) panic("sfnode_make_stale(%s) not in sfnodes", node->sf_path); avl_remove(&sfnodes, node); node->sf_is_stale = 1; if (avl_find(&stale_sfnodes, node, &where) != NULL) panic("sffs_make_stale(%s) duplicates", node->sf_path); avl_insert(&stale_sfnodes, node, where); } }
status_t VBoxMouse::Start(const char *device, void *cookie) { #if 0 status_t err; int rc; uint32_t fFeatures = 0; Log(("VBoxMouse::%s()\n", __FUNCTION__)); rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL); if (RT_SUCCESS(rc)) rc = VbglR3SetMouseStatus(fFeatures | VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL); if (!RT_SUCCESS(rc)) { LogRel(("VBoxMouse: Error switching guest mouse into absolute mode: %d\n", rc)); return B_DEVICE_NOT_FOUND; } err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxMouse", B_NORMAL_PRIORITY, this); if (err >= B_OK) { resume_thread(fServiceThreadID); return B_OK; } else LogRel(("VBoxMouse: Error starting service thread: 0x%08lx\n", err)); // release the mouse rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL); if (RT_SUCCESS(rc)) rc = VbglR3SetMouseStatus(fFeatures & ~VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE & ~VMMDEV_MOUSE_NEW_PROTOCOL); return B_ERROR; #endif status_t err = B_OK; int rc; uint32_t fFeatures = 0; LogFlowFunc(("device=%s cookie=%p\n", device, cookie)); rc = vboxMouseAcquire(); if (RT_SUCCESS(rc)) { err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxMouse", B_NORMAL_PRIORITY, this); if (err >= B_OK) { resume_thread(fServiceThreadID); return B_OK; } else LogRel(("VBoxMouse::Start Error starting service thread: 0x%08lx\n", err)); vboxMouseRelease(); err = B_ERROR; } else { LogRel(("VBoxMouse::Start vboxMouseAcquire failed. rc=%d\n", rc)); err = B_DEVICE_NOT_FOUND; } return err; }
STDMETHODIMP VBoxDnDDropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { AssertPtrReturn(pDataObject, E_INVALIDARG); AssertPtrReturn(pdwEffect, E_INVALIDARG); #ifdef DEBUG LogFlowFunc(("mFormatEtc.cfFormat=%RI16 (%s), pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n", mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat), pDataObject, grfKeyState, pt.x, pt.y)); #endif HRESULT hr = S_OK; if (mFormatEtc.cfFormat) /* Did we get a supported format yet? */ { /* Make sure the data object's data format is still the same * as we got it in DragEnter(). */ hr = pDataObject->QueryGetData(&mFormatEtc); AssertMsg(SUCCEEDED(hr), ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16 (%s), hr=%Rhrc\n", mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat), hr)); } int rc = VINF_SUCCESS; if (SUCCEEDED(hr)) { STGMEDIUM stgMed; hr = pDataObject->GetData(&mFormatEtc, &stgMed); if (SUCCEEDED(hr)) { /* * First stage: Prepare the access to the storage medium. * For now we only support HGLOBAL stuff. */ PVOID pvData = NULL; /** @todo Put this in an own union? */ switch (mFormatEtc.tymed) { case TYMED_HGLOBAL: pvData = GlobalLock(stgMed.hGlobal); if (!pvData) { LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n", RTErrConvertFromWin32(GetLastError()))); rc = VERR_INVALID_HANDLE; hr = E_INVALIDARG; /* Set special hr for OLE. */ } break; default: AssertMsgFailed(("Storage medium type %RI32 supported\n", mFormatEtc.tymed)); rc = VERR_NOT_SUPPORTED; hr = DV_E_TYMED; /* Set special hr for OLE. */ break; } if (RT_SUCCESS(rc)) { /* Second stage: Do the actual copying of the data object's data, based on the storage medium type. */ switch (mFormatEtc.cfFormat) { case CF_UNICODETEXT: { AssertPtr(pvData); size_t cbSize = GlobalSize(pvData); LogFlowFunc(("CF_UNICODETEXT 0x%p got %zu bytes\n", pvData, cbSize)); if (cbSize) { char *pszText = NULL; rc = RTUtf16ToUtf8((PCRTUTF16)pvData, &pszText); if (RT_SUCCESS(rc)) { mpvData = (void *)pszText; mcbData = strlen(pszText) + 1; /* Include termination. */ /* Note: Don't free data of pszText, mpvData now owns it. */ } } break; } case CF_TEXT: { AssertPtr(pvData); size_t cbSize = GlobalSize(pvData); LogFlowFunc(("CF_TEXT 0x%p got %zu bytes\n", pvData, cbSize)); if (cbSize) { char *pszText = NULL; rc = RTStrCurrentCPToUtf8(&pszText, (char *)pvData); if (RT_SUCCESS(rc)) { mpvData = (void *)pszText; mcbData = strlen(pszText) + 1; /* Include termination. */ /* Note: Don't free data of pszText, mpvData now owns it. */ } } break; } case CF_HDROP: { AssertPtr(pvData); /* Convert to a string list, separated by \r\n. */ DROPFILES *pDropFiles = (DROPFILES *)pvData; AssertPtr(pDropFiles); bool fUnicode = RT_BOOL(pDropFiles->fWide); /* Get the offset of the file list. */ Assert(pDropFiles->pFiles >= sizeof(DROPFILES)); /* Note: This is *not* pDropFiles->pFiles! DragQueryFile only * will work with the plain storage medium pointer! */ HDROP hDrop = (HDROP)(pvData); /* First, get the file count. */ /** @todo Does this work on Windows 2000 / NT4? */ char *pszFiles = NULL; uint32_t cchFiles = 0; UINT cFiles = DragQueryFile(hDrop, UINT32_MAX /* iFile */, NULL /* lpszFile */, 0 /* cchFile */); LogFlowFunc(("CF_HDROP got %RU16 file(s)\n", cFiles)); for (UINT i = 0; i < cFiles; i++) { UINT cch = DragQueryFile(hDrop, i /* File index */, NULL /* Query size first */, 0 /* cchFile */); Assert(cch); if (RT_FAILURE(rc)) break; char *pszFile = NULL; /* UTF-8 version. */ UINT cchFile = 0; if (fUnicode) { /* Allocate enough space (including terminator). */ WCHAR *pwszFile = (WCHAR *)RTMemAlloc((cch + 1) * sizeof(WCHAR)); if (pwszFile) { cchFile = DragQueryFileW(hDrop, i /* File index */, pwszFile, cch + 1 /* Include terminator */); AssertMsg(cchFile == cch, ("cchCopied (%RU16) does not match cchFile (%RU16)\n", cchFile, cch)); int rc2 = RTUtf16ToUtf8(pwszFile, &pszFile); AssertRC(rc2); } else rc = VERR_NO_MEMORY; } else /* ANSI */ { /* Allocate enough space (including terminator). */ pszFile = (char *)RTMemAlloc((cch + 1) * sizeof(char)); if (pszFile) { cchFile = DragQueryFileA(hDrop, i /* File index */, pszFile, cchFile + 1 /* Include terminator */); AssertMsg(cchFile == cch, ("cchCopied (%RU16) does not match cchFile (%RU16)\n", cchFile, cch)); } else rc = VERR_NO_MEMORY; } if (RT_SUCCESS(rc)) { LogFlowFunc(("\tFile: %s (cchFile=%RU32)\n", pszFile, cchFile)); rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, pszFile, cchFile); if (RT_SUCCESS(rc)) cchFiles += cchFile; } if (pszFile) RTMemFree(pszFile); if (RT_FAILURE(rc)) break; /* Add separation between filenames. * Note: Also do this for the last element of the list. */ rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, "\r\n", 2 /* Bytes */); if (RT_SUCCESS(rc)) cchFiles += 2; /* Include \r\n */ } if (RT_SUCCESS(rc)) { cchFiles += 1; /* Add string termination. */ uint32_t cbFiles = cchFiles * sizeof(char); LogFlowFunc(("cFiles=%u, cchFiles=%RU32, cbFiles=%RU32, pszFiles=0x%p\n", cFiles, cchFiles, cbFiles, pszFiles)); /* Translate the list into URI elements. */ DnDURIList lstURI; rc = lstURI.AppendNativePathsFromList(pszFiles, cbFiles, DNDURILIST_FLAGS_ABSOLUTE_PATHS); if (RT_SUCCESS(rc)) { RTCString strRoot = lstURI.RootToString(); size_t cbRoot = strRoot.length() + 1; /* Include termination */ mpvData = RTMemAlloc(cbRoot); if (mpvData) { memcpy(mpvData, strRoot.c_str(), cbRoot); mcbData = cbRoot; } else rc = VERR_NO_MEMORY; } } LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n", rc, pszFiles, cFiles, cchFiles)); if (pszFiles) RTStrFree(pszFiles); break; } default: /* Note: Should not happen due to the checks done in DragEnter(). */ AssertMsgFailed(("Format of type %RI16 (%s) not supported\n", mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat))); hr = DV_E_CLIPFORMAT; /* Set special hr for OLE. */ break; } /* * Third stage: Unlock + release access to the storage medium again. */ switch (mFormatEtc.tymed) { case TYMED_HGLOBAL: GlobalUnlock(stgMed.hGlobal); break; default: AssertMsgFailed(("Really should not happen -- see init stage!\n")); break; } } /* Release storage medium again. */ ReleaseStgMedium(&stgMed); /* Signal waiters. */ mDroppedRc = rc; RTSemEventSignal(hEventDrop); } } if (RT_SUCCESS(rc)) { /* Note: pt is not used since we don't need to differentiate within our * proxy window. */ *pdwEffect = VBoxDnDDropTarget::GetDropEffect(grfKeyState, *pdwEffect); } else *pdwEffect = DROPEFFECT_NONE; if (mpWndParent) mpWndParent->hide(); LogFlowFunc(("Returning with hr=%Rhrc (%Rrc), mFormatEtc.cfFormat=%RI16 (%s), *pdwEffect=%RI32\n", hr, rc, mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat), *pdwEffect)); return hr; }
STDMETHODIMP VBoxDnDDropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { AssertPtrReturn(pDataObject, E_INVALIDARG); AssertPtrReturn(pdwEffect, E_INVALIDARG); LogFlowFunc(("pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n", pDataObject, grfKeyState, pt.x, pt.y, *pdwEffect)); reset(); /** @todo At the moment we only support one DnD format at a time. */ /* Try different formats. CF_HDROP is the most common one, so start * with this. */ FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; HRESULT hr = pDataObject->QueryGetData(&fmtEtc); if (hr == S_OK) { mFormats = "text/uri-list"; } else { LogFlowFunc(("CF_HDROP not wanted, hr=%Rhrc\n", hr)); /* So we couldn't retrieve the data in CF_HDROP format; try with * CF_UNICODETEXT + CF_TEXT formats now. Rest stays the same. */ fmtEtc.cfFormat = CF_UNICODETEXT; hr = pDataObject->QueryGetData(&fmtEtc); if (hr == S_OK) { mFormats = "text/plain;charset=utf-8"; } else { LogFlowFunc(("CF_UNICODETEXT not wanted, hr=%Rhrc\n", hr)); fmtEtc.cfFormat = CF_TEXT; hr = pDataObject->QueryGetData(&fmtEtc); if (hr == S_OK) { mFormats = "text/plain;charset=utf-8"; } else { LogFlowFunc(("CF_TEXT not wanted, hr=%Rhrc\n", hr)); fmtEtc.cfFormat = 0; /* Mark it to not supported. */ } } } /* Did we find a format that we support? */ if (fmtEtc.cfFormat) { LogFlowFunc(("Found supported format %RI16 (%s)\n", fmtEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(fmtEtc.cfFormat))); /* Make a copy of the FORMATETC structure so that we later can * use this for comparrison and stuff. */ /** Note: The DVTARGETDEVICE member only is a shallow copy for now! */ memcpy(&mFormatEtc, &fmtEtc, sizeof(FORMATETC)); /* Which drop effect we're going to use? */ /* Note: pt is not used since we don't need to differentiate within our * proxy window. */ *pdwEffect = VBoxDnDDropTarget::GetDropEffect(grfKeyState, *pdwEffect); } else { /* No or incompatible data -- so no drop effect required. */ *pdwEffect = DROPEFFECT_NONE; switch (hr) { case ERROR_INVALID_FUNCTION: { LogRel(("DnD: Drag and drop format is not supported by VBoxTray\n")); /* Enumerate supported source formats. This shouldn't happen too often * on day to day use, but still keep it in here. */ IEnumFORMATETC *pEnumFormats; HRESULT hr2 = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormats); if (SUCCEEDED(hr2)) { LogRel(("DnD: The following formats were offered to us:\n")); FORMATETC curFormatEtc; while (pEnumFormats->Next(1, &curFormatEtc, NULL /* pceltFetched */) == S_OK) { WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */ hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName, sizeof(wszCfName) / sizeof(WCHAR)); LogRel(("\tcfFormat=%RI16 (%s), tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n", curFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(curFormatEtc.cfFormat), curFormatEtc.tymed, curFormatEtc.dwAspect, wszCfName, hr2)); } pEnumFormats->Release(); } break; } default: break; } } LogFlowFunc(("Returning cfFormat=%RI16, pdwEffect=%ld, hr=%Rhrc\n", fmtEtc.cfFormat, *pdwEffect, hr)); return hr; }
/* static */ const char* VBoxDnDDataObject::ClipboardFormatToString(CLIPFORMAT fmt) { #ifdef VBOX_DND_DEBUG_FORMATS char szFormat[128]; if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat))) LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat)); #endif switch (fmt) { case 1: return "CF_TEXT"; case 2: return "CF_BITMAP"; case 3: return "CF_METAFILEPICT"; case 4: return "CF_SYLK"; case 5: return "CF_DIF"; case 6: return "CF_TIFF"; case 7: return "CF_OEMTEXT"; case 8: return "CF_DIB"; case 9: return "CF_PALETTE"; case 10: return "CF_PENDATA"; case 11: return "CF_RIFF"; case 12: return "CF_WAVE"; case 13: return "CF_UNICODETEXT"; case 14: return "CF_ENHMETAFILE"; case 15: return "CF_HDROP"; case 16: return "CF_LOCALE"; case 17: return "CF_DIBV5"; case 18: return "CF_MAX"; case 49158: return "FileName"; case 49159: return "FileNameW"; case 49161: return "DATAOBJECT"; case 49171: return "Ole Private Data"; case 49314: return "Shell Object Offsets"; case 49316: return "File Contents"; case 49317: return "File Group Descriptor"; case 49323: return "Preferred Drop Effect"; case 49380: return "Shell Object Offsets"; case 49382: return "FileContents"; case 49383: return "FileGroupDescriptor"; case 49389: return "Preferred DropEffect"; case 49268: return "Shell IDList Array"; case 49619: return "RenPrivateFileAttachments"; default: break; } return "unknown"; }
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; }
void VBoxDnDDataObject::SetStatus(Status status) { LogFlowFunc(("Setting status to %ld\n", status)); mStatus = status; }
/** * 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; }
/** * @callback_method_impl{FNIOMIOPORTOUT} */ PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb) { PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PPARALLELPORT); int rc = VINF_SUCCESS; RT_NOREF_PV(pvUser); if (cb == 1) { uint8_t u8 = u32; Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, uPort, u32)); uPort &= 7; switch (uPort) { case 0: #ifndef IN_RING3 NOREF(u8); rc = VINF_IOM_R3_IOPORT_WRITE; #else pThis->regData = u8; if (RT_LIKELY(pThis->pDrvHostParallelConnector)) { LogFlowFunc(("Set data lines 0x%X\n", u8)); rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_SPP); AssertRC(rc); } #endif break; case 1: break; case 2: /* Set the reserved bits to one */ u8 |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7); if (u8 != pThis->regControl) { #ifndef IN_RING3 return VINF_IOM_R3_IOPORT_WRITE; #else if (RT_LIKELY(pThis->pDrvHostParallelConnector)) { /* Set data direction. */ if (u8 & LPT_CONTROL_ENABLE_BIDIRECT) rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, false /* fForward */); else rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, true /* fForward */); AssertRC(rc); u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */ rc = pThis->pDrvHostParallelConnector->pfnWriteControl(pThis->pDrvHostParallelConnector, u8); AssertRC(rc); } else u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */ pThis->regControl = u8; #endif } break; case 3: #ifndef IN_RING3 NOREF(u8); rc = VINF_IOM_R3_IOPORT_WRITE; #else pThis->regEppAddr = u8; if (RT_LIKELY(pThis->pDrvHostParallelConnector)) { LogFlowFunc(("Write EPP address 0x%X\n", u8)); rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR); AssertRC(rc); } #endif break; case 4: #ifndef IN_RING3 NOREF(u8); rc = VINF_IOM_R3_IOPORT_WRITE; #else pThis->regEppData = u8; if (RT_LIKELY(pThis->pDrvHostParallelConnector)) { LogFlowFunc(("Write EPP data 0x%X\n", u8)); rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_DATA); AssertRC(rc); } #endif break; case 5: break; case 6: break; case 7: default: break; } } else AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", uPort, cb, u32)); return rc; }
/** * Retrieves the data stored in this object and store the result in * pMedium. * * @return IPRT status code. * @return HRESULT * @param pFormatEtc * @param pMedium */ STDMETHODIMP VBoxDnDDataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { AssertPtrReturn(pFormatEtc, DV_E_FORMATETC); AssertPtrReturn(pMedium, DV_E_FORMATETC); ULONG lIndex; if (!LookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */ return DV_E_FORMATETC; if (lIndex >= mcFormats) /* Paranoia. */ return DV_E_FORMATETC; LogFlowFunc(("pFormatEtc=%p, pMedium=%p\n", pFormatEtc, pMedium)); FORMATETC *pThisFormat = &mpFormatEtc[lIndex]; AssertPtr(pThisFormat); STGMEDIUM *pThisMedium = &mpStgMedium[lIndex]; AssertPtr(pThisMedium); HRESULT hr = DV_E_FORMATETC; LogFlowFunc(("mStatus=%ld\n", mStatus)); if (mStatus == Dropping) { LogFlowFunc(("Waiting for event ...\n")); int rc2 = RTSemEventWait(mSemEvent, RT_INDEFINITE_WAIT); LogFlowFunc(("rc=%Rrc, mStatus=%ld\n", rc2, mStatus)); } if (mStatus == Dropped) { LogFlowFunc(("cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n", pThisFormat->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat), pThisFormat->tymed, pThisFormat->dwAspect)); LogFlowFunc(("Got strFormat=%s, pvData=%p, cbData=%RU32\n", mstrFormat.c_str(), mpvData, mcbData)); if (mstrFormat.equalsIgnoreCase("text/uri-list")) { RTCList<RTCString> lstFilesURI = RTCString((char*)mpvData, mcbData).split("\r\n"); RTCList<RTCString> lstFiles; for (size_t i = 0; i < lstFilesURI.size(); i++) { /* Extract path from URI. */ char *pszPath = RTUriPath(lstFilesURI.at(i).c_str()); if ( pszPath && strlen(pszPath) > 1) { pszPath++; /** @todo Skip first '/' (part of URI). Correct? */ pszPath = RTPathChangeToDosSlashes(pszPath, false /* fForce */); lstFiles.append(pszPath); } } #ifdef DEBUG LogFlowFunc(("Files (%zu)\n", lstFiles.size())); for (size_t i = 0; i < lstFiles.size(); i++) LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).c_str())); #endif #if 0 if ( (pFormatEtc->tymed & TYMED_ISTREAM) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILECONTENTS)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR)) { } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT)) { HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD)); DWORD *pdwEffect = (DWORD *)GlobalLock(hData); AssertPtr(pdwEffect); *pdwEffect = DROPEFFECT_COPY; GlobalUnlock(hData); pMedium->hGlobal = hData; pMedium->tymed = TYMED_HGLOBAL; } else #endif if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_TEXT)) { pMedium->hGlobal = GlobalAlloc(GHND, mcbData + 1); if (pMedium->hGlobal) { /** @todo Not working yet -- needs URI to plain ASCII conversion. */ char *pcDst = (char *)GlobalLock(pMedium->hGlobal); memcpy(pcDst, mpvData, mcbData); pcDst[mcbData] = '\0'; GlobalUnlock(pMedium->hGlobal); hr = S_OK; } } else if ( (pFormatEtc->tymed & TYMED_HGLOBAL) && (pFormatEtc->dwAspect == DVASPECT_CONTENT) && (pFormatEtc->cfFormat == CF_HDROP)) { int rc = VINF_SUCCESS; size_t cchFiles = 0; /* Number of ASCII characters. */ for (size_t i = 0; i < lstFiles.size(); i++) { cchFiles += strlen(lstFiles.at(i).c_str()); cchFiles += 1; /* Terminating '\0'. */ } size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16)); DROPFILES *pBuf = (DROPFILES *)RTMemAllocZ(cbBuf); if (pBuf) { pBuf->pFiles = sizeof(DROPFILES); pBuf->fWide = 1; /* We use unicode. Always. */ uint8_t *pCurFile = (uint8_t *)pBuf + pBuf->pFiles; AssertPtr(pCurFile); for (size_t i = 0; i < lstFiles.size() && RT_SUCCESS(rc); i++) { size_t cchCurFile; PRTUTF16 pwszFile; rc = RTStrToUtf16(lstFiles.at(i).c_str(), &pwszFile); if (RT_SUCCESS(rc)) { cchCurFile = RTUtf16Len(pwszFile); Assert(cchCurFile); memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16)); RTUtf16Free(pwszFile); } else break; pCurFile += cchCurFile * sizeof(RTUTF16); /* Terminate current file name. */ *pCurFile = L'\0'; pCurFile += sizeof(RTUTF16); } if (RT_SUCCESS(rc)) { *pCurFile = L'\0'; /* Final list terminator. */ pMedium->tymed = TYMED_HGLOBAL; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, cbBuf); if (pMedium->hGlobal) { LPVOID pMem = GlobalLock(pMedium->hGlobal); if (pMem) { memcpy(pMem, pBuf, cbBuf); GlobalUnlock(pMedium->hGlobal); hr = S_OK; } } } RTMemFree(pBuf); } else rc = VERR_NO_MEMORY; if (RT_FAILURE(rc)) hr = DV_E_FORMATETC; } } } if (FAILED(hr)) { LogFlowFunc(("Copying medium ...\n")); switch (pThisMedium->tymed) { case TYMED_HGLOBAL: pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal, pThisFormat->cfFormat, NULL); break; default: break; } pMedium->tymed = pThisFormat->tymed; pMedium->pUnkForRelease = NULL; } LogFlowFunc(("hr=%Rhrc\n", hr)); return hr; }
/** * Construct a block driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { int rc = VINF_SUCCESS; PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Initialize the instance data. */ pThis->pDrvIns = pDrvIns; pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsiRequestSend; pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface; pThis->IPort.pfnQueryDeviceLocation = drvscsiQueryDeviceLocation; pThis->IPortAsync.pfnTransferCompleteNotify = drvscsiTransferCompleteNotify; pThis->hQueueRequests = NIL_RTREQQUEUE; /* Query the SCSI port interface above. */ pThis->pDevScsiPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISCSIPORT); AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE); /* Query the optional LED interface above. */ pThis->pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); if (pThis->pLedPort != NULL) { /* Get The Led. */ rc = pThis->pLedPort->pfnQueryStatusLed(pThis->pLedPort, 0, &pThis->pLed); if (RT_FAILURE(rc)) pThis->pLed = &pThis->Led; } else pThis->pLed = &pThis->Led; /* * Validate and read configuration. */ if (!CFGMR3AreValuesValid(pCfg, "NonRotationalMedium\0Readonly\0")) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, N_("SCSI configuration error: unknown option specified")); rc = CFGMR3QueryBoolDef(pCfg, "NonRotationalMedium", &pThis->fNonRotational, false); if (RT_FAILURE(rc)) return PDMDRV_SET_ERROR(pDrvIns, rc, N_("SCSI configuration error: failed to read \"NonRotationalMedium\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "Readonly", &pThis->fReadonly, false); if (RT_FAILURE(rc)) return PDMDRV_SET_ERROR(pDrvIns, rc, N_("SCSI configuration error: failed to read \"Readonly\" as boolean")); /* * Try attach driver below and query it's block interface. */ rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase); AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc); /* * Query the block and blockbios interfaces. */ pThis->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCK); if (!pThis->pDrvBlock) { AssertMsgFailed(("Configuration error: No block interface!\n")); return VERR_PDM_MISSING_INTERFACE; } pThis->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKBIOS); if (!pThis->pDrvBlockBios) { AssertMsgFailed(("Configuration error: No block BIOS interface!\n")); return VERR_PDM_MISSING_INTERFACE; } pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT); /* Try to get the optional async block interface. */ pThis->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKASYNC); PDMBLOCKTYPE enmType = pThis->pDrvBlock->pfnGetType(pThis->pDrvBlock); if (enmType != PDMBLOCKTYPE_HARD_DISK) return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS, N_("Only hard disks are currently supported as SCSI devices (enmType=%d)"), enmType); /* Create VSCSI device and LUN. */ pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize = drvscsiGetSize; pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue; pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags = drvscsiGetFeatureFlags; rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiVScsiReqCompleted, pThis); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n"), rc); rc = VSCSILunCreate(&pThis->hVScsiLun, VSCSILUNTYPE_SBC, &pThis->VScsiIoCallbacks, pThis); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI LUN rc=%Rrc\n"), rc); rc = VSCSIDeviceLunAttach(pThis->hVScsiDevice, pThis->hVScsiLun, 0); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to attached the LUN to the SCSI device\n"), rc); /* Register statistics counter. */ /** @todo aeichner: Find a way to put the instance number of the attached * controller device when we support more than one controller of the same type. * At the moment we have the 0 hardcoded. */ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data read.", "/Devices/SCSI0/%d/ReadBytes", pDrvIns->iInstance); PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data written.", "/Devices/SCSI0/%d/WrittenBytes", pDrvIns->iInstance); pThis->StatIoDepth = 0; PDMDrvHlpSTAMRegisterF(pDrvIns, (void *)&pThis->StatIoDepth, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of active tasks.", "/Devices/SCSI0/%d/IoDepth", pDrvIns->iInstance); if (!pThis->pDrvBlockAsync) { /* Create request queue. */ rc = RTReqQueueCreate(&pThis->hQueueRequests); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n"), rc); /* Create I/O thread. */ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pAsyncIOThread, pThis, drvscsiAsyncIOLoop, drvscsiAsyncIOLoopWakeup, 0, RTTHREADTYPE_IO, "SCSI async IO"); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create async I/O thread rc=%Rrc\n"), rc); LogRel(("SCSI#%d: using normal I/O\n", pDrvIns->iInstance)); } else LogRel(("SCSI#%d: using async I/O\n", pDrvIns->iInstance)); if ( pThis->pDrvBlock->pfnDiscard || ( pThis->pDrvBlockAsync && pThis->pDrvBlockAsync->pfnStartDiscard)) LogRel(("SCSI#%d: Enabled UNMAP support\n")); return VINF_SUCCESS; }
VBoxDnDDataObject::VBoxDnDDataObject(FORMATETC *pFormatEtc, STGMEDIUM *pStgMed, ULONG cFormats) : mStatus(Uninitialized), mRefCount(1), mcFormats(0), mpvData(NULL), mcbData(0) { HRESULT hr; /* Make sure that there's enough room for our fixed formats. */ ULONG cAllFormats = cFormats + 1; try { mpFormatEtc = new FORMATETC[cAllFormats]; RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cAllFormats); mpStgMedium = new STGMEDIUM[cAllFormats]; RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cAllFormats); if ( pFormatEtc && pStgMed) { for (ULONG i = 0; i < cFormats; i++) { LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n", i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect)); mpFormatEtc[i] = pFormatEtc[i]; mpStgMedium[i] = pStgMed[i]; } } hr = S_OK; } catch (std::bad_alloc &) { hr = E_OUTOFMEMORY; } if (SUCCEEDED(hr)) { int rc2 = RTSemEventCreate(&mSemEvent); AssertRC(rc2); /* Most commonly used format. */ RegisterFormat(&mpFormatEtc[cFormats], CF_HDROP); mpStgMedium[cFormats++].tymed = TYMED_HGLOBAL; #if 0 /* IStream. */ RegisterFormat(&mpFormatEtc[cFormats++], RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR)); RegisterFormat(&mpFormatEtc[cFormats++], RegisterClipboardFormat(CFSTR_FILECONTENTS), TYMED_ISTREAM, 0 /* lIndex */); /* Required for e.g. Windows Media Player. */ RegisterFormat(&mpFormatEtc[cFormats++], RegisterClipboardFormat(CFSTR_FILENAME)); RegisterFormat(&mpFormatEtc[cFormats++], RegisterClipboardFormat(CFSTR_FILENAMEW)); RegisterFormat(&mpFormatEtc[cFormats++], RegisterClipboardFormat(CFSTR_SHELLIDLIST)); RegisterFormat(&mpFormatEtc[cFormats++], RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET)); #endif mcFormats = cFormats; mStatus = Initialized; } LogFlowFunc(("cFormats=%RU32, hr=%Rhrc\n", cFormats, hr)); }
/** * Opens the USB device. * * @returns VBox status code. * @param pProxyDev The device instance. * @param pszAddress The unique device identifier. * The format of this string is "VendorId:ProducIt:Release:StaticPath". * @param pvBackend Backend specific pointer, unused for the solaris backend. */ static DECLCALLBACK(int) usbProxySolarisOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend) { PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL); LogFlowFunc((USBPROXY ":usbProxySolarisOpen pProxyDev=%p pszAddress=%s pvBackend=%p\n", pProxyDev, pszAddress, pvBackend)); /* * Initialize our USB R3 lib. */ int rc = USBLibInit(); if (RT_SUCCESS(rc)) { /* * Allocate and initialize the solaris backend data. */ AssertCompile(PATH_MAX >= MAXPATHLEN); char szDeviceIdent[PATH_MAX+48]; rc = RTStrPrintf(szDeviceIdent, sizeof(szDeviceIdent), "%s", pszAddress); if (RT_SUCCESS(rc)) { rc = RTCritSectInit(&pDevSol->CritSect); if (RT_SUCCESS(rc)) { /* * Create wakeup pipe. */ rc = RTPipeCreate(&pDevSol->hPipeWakeupR, &pDevSol->hPipeWakeupW, 0); if (RT_SUCCESS(rc)) { int Instance; char *pszDevicePath = NULL; rc = USBLibGetClientInfo(szDeviceIdent, &pszDevicePath, &Instance); if (RT_SUCCESS(rc)) { pDevSol->pszDevicePath = pszDevicePath; /* * Open the client driver. */ RTFILE hFile; rc = RTFileOpen(&hFile, pDevSol->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); if (RT_SUCCESS(rc)) { pDevSol->hFile = hFile; pDevSol->pProxyDev = pProxyDev; /* * Verify client driver version. */ VBOXUSBREQ_GET_VERSION GetVersionReq; bzero(&GetVersionReq, sizeof(GetVersionReq)); rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_VERSION, &GetVersionReq, sizeof(GetVersionReq)); if (RT_SUCCESS(rc)) { if ( GetVersionReq.u32Major == VBOXUSB_VERSION_MAJOR && GetVersionReq.u32Minor >= VBOXUSB_VERSION_MINOR) { /* * Try & get the current cached config from Solaris. */ usbProxySolarisGetActiveConfig(pDevSol); return VINF_SUCCESS; } else { LogRel((USBPROXY ":version mismatch! driver v%d.%d expecting ~v%d.%d\n", GetVersionReq.u32Major, GetVersionReq.u32Minor, VBOXUSB_VERSION_MAJOR, VBOXUSB_VERSION_MINOR)); rc = VERR_VERSION_MISMATCH; } } else LogRel((USBPROXY ":failed to query driver version. rc=%Rrc\n", rc)); RTFileClose(pDevSol->hFile); pDevSol->hFile = NIL_RTFILE; pDevSol->pProxyDev = NULL; } else LogRel((USBPROXY ":failed to open device. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath)); RTStrFree(pDevSol->pszDevicePath); pDevSol->pszDevicePath = NULL; } else { LogRel((USBPROXY ":failed to get client info. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath)); if (rc == VERR_NOT_FOUND) rc = VERR_OPEN_FAILED; } RTPipeClose(pDevSol->hPipeWakeupR); RTPipeClose(pDevSol->hPipeWakeupW); } RTCritSectDelete(&pDevSol->CritSect); } else LogRel((USBPROXY ":RTCritSectInit failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress)); } else LogRel((USBPROXY ":RTStrAPrintf failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress)); } else LogRel((USBPROXY ":USBLibInit failed. rc=%Rrc\n", rc)); USBLibTerm(); return rc; }
/** * Only required for IStream / IStorage interfaces. * * @return IPRT status code. * @return HRESULT * @param pFormatEtc * @param pMedium */ STDMETHODIMP VBoxDnDDataObject::GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { LogFlowFunc(("\n")); return DATA_E_FORMATETC; }
static LRESULT vboxClipboardProcessMsg(PVBOXCLIPBOARDCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { AssertPtr(pCtx); const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win; LRESULT rc = 0; switch (msg) { case WM_CLIPBOARDUPDATE: { Log(("WM_CLIPBOARDUPDATE\n")); if (GetClipboardOwner() != hwnd) { /* Clipboard was updated by another application. */ uint32_t uFormats; int vboxrc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats); if (RT_SUCCESS(vboxrc)) vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats); } } break; case WM_CHANGECBCHAIN: { if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI)) { rc = DefWindowProc(hwnd, msg, wParam, lParam); break; } HWND hWndRemoved = (HWND)wParam; HWND hWndNext = (HWND)lParam; LogFlowFunc(("WM_CHANGECBCHAIN: hWndRemoved=%p, hWndNext=%p, hWnd=%p\n", hWndRemoved, hWndNext, pWinCtx->hWnd)); if (hWndRemoved == pWinCtx->hWndNextInChain) { /* The window that was next to our in the chain is being removed. * Relink to the new next window. */ pWinCtx->hWndNextInChain = hWndNext; } else { if (pWinCtx->hWndNextInChain) { /* Pass the message further. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pWinCtx->hWndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS, &dwResult); if (!rc) rc = (LRESULT)dwResult; } } } break; case WM_DRAWCLIPBOARD: { LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pWinCtx->hWnd)); if (GetClipboardOwner() != hwnd) { /* Clipboard was updated by another application. */ /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */ uint32_t uFormats; int vboxrc = VBoxClipboardWinGetFormats(pWinCtx, &uFormats); if (RT_SUCCESS(vboxrc)) vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats); } if (pWinCtx->hWndNextInChain) { /* Pass the message to next windows in the clipboard chain. */ SendMessageTimeout(pWinCtx->hWndNextInChain, msg, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS, NULL); } } break; case WM_TIMER: { if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI)) break; HWND hViewer = GetClipboardViewer(); /* Re-register ourselves in the clipboard chain if our last ping * timed out or there seems to be no valid chain. */ if (!hViewer || pWinCtx->oldAPI.fCBChainPingInProcess) { VBoxClipboardWinRemoveFromCBChain(pWinCtx); VBoxClipboardWinAddToCBChain(pWinCtx); } /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be * processed by ourselves to the chain. */ pWinCtx->oldAPI.fCBChainPingInProcess = TRUE; hViewer = GetClipboardViewer(); if (hViewer) SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pWinCtx->hWndNextInChain, (LPARAM)pWinCtx->hWndNextInChain, VBoxClipboardWinChainPingProc, (ULONG_PTR)pWinCtx); } break; case WM_CLOSE: { /* Do nothing. Ignore the message. */ } break; case WM_RENDERFORMAT: { /* Insert the requested clipboard format data into the clipboard. */ uint32_t fFormat = VBOX_SHARED_CLIPBOARD_FMT_NONE; const UINT cfFormat = (UINT)wParam; switch (cfFormat) { case CF_UNICODETEXT: fFormat = VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: fFormat = VBOX_SHARED_CLIPBOARD_FMT_BITMAP; break; #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST case CF_HDROP: fFormat = VBOX_SHARED_CLIPBOARD_FMT_URI_LIST; break; #endif default: if (cfFormat >= 0xC000) /** @todo r=andy Explain. */ { TCHAR szFormatName[256]; /** @todo r=andy Do we need Unicode support here as well? */ int cActual = GetClipboardFormatName(cfFormat, szFormatName, sizeof(szFormatName) / sizeof(TCHAR)); if (cActual) { if (strcmp(szFormatName, "HTML Format") == 0) fFormat = VBOX_SHARED_CLIPBOARD_FMT_HTML; } } break; } LogFunc(("WM_RENDERFORMAT: format=%u -> fFormat=0x%x\n", cfFormat, fFormat)); if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_NONE) { /* Unsupported clipboard format is requested. */ LogRel(("Clipboard: Unsupported clipboard format requested (0x%x)\n", fFormat)); VBoxClipboardWinClear(); } #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST else if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) { } #endif else { const uint32_t cbPrealloc = _4K; uint32_t cb = 0; /* Preallocate a buffer, most of small text transfers will fit into it. */ HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc); LogFlowFunc(("Preallocated handle hMem = %p\n", hMem)); if (hMem) { void *pMem = GlobalLock(hMem); LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cbPrealloc, &cb); LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc)); if (RT_SUCCESS(vboxrc)) { if (cb == 0) { /* 0 bytes returned means the clipboard is empty. * Deallocate the memory and set hMem to NULL to get to * the clipboard empty code path. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else if (cb > cbPrealloc) { GlobalUnlock(hMem); /* The preallocated buffer is too small, adjust the size. */ hMem = GlobalReAlloc(hMem, cb, 0); LogFlowFunc(("Reallocated hMem = %p\n", hMem)); if (hMem) { pMem = GlobalLock(hMem); LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ uint32_t cbNew = 0; vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cb, &cbNew); LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew)); if (RT_SUCCESS(vboxrc) && cbNew <= cb) { cb = cbNew; } else { GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } } else { GlobalFree(hMem); hMem = NULL; } } } if (hMem) { /* pMem is the address of the data. cb is the size of returned data. */ /* Verify the size of returned text, the memory block for clipboard * must have the exact string size. */ if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { size_t cbActual = 0; HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual); if (FAILED(hrc)) { /* Discard invalid data. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else { /* cbActual is the number of bytes, excluding those used * for the terminating null character. */ cb = (uint32_t)(cbActual + 2); } } } if (hMem) { GlobalUnlock(hMem); hMem = GlobalReAlloc(hMem, cb, 0); LogFlowFunc(("Reallocated hMem = %p\n", hMem)); if (hMem) { /* 'hMem' contains the host clipboard data. * size is 'cb' and format is 'format'. */ HANDLE hClip = SetClipboardData(cfFormat, hMem); LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip)); if (hClip) { /* The hMem ownership has gone to the system. Finish the processing. */ break; } /* Cleanup follows. */ } } } if (hMem) GlobalUnlock(hMem); } if (hMem) GlobalFree(hMem); } /* Something went wrong. */ VBoxClipboardWinClear(); } } break; case WM_RENDERALLFORMATS: { /* Do nothing. The clipboard formats will be unavailable now, because the * windows is to be destroyed and therefore the guest side becomes inactive. */ int vboxrc = VBoxClipboardWinOpen(hwnd); if (RT_SUCCESS(vboxrc)) { VBoxClipboardWinClear(); VBoxClipboardWinClose(); } } break; case VBOX_CLIPBOARD_WM_SET_FORMATS: { /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */ VBOXCLIPBOARDFORMATS fFormats = (uint32_t)lParam; LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: fFormats=0x%x\n", fFormats)); int vboxrc = VBoxClipboardWinOpen(hwnd); if (RT_SUCCESS(vboxrc)) { VBoxClipboardWinClear(); HANDLE hClip = NULL; if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) hClip = SetClipboardData(CF_UNICODETEXT, NULL); if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) hClip = SetClipboardData(CF_DIB, NULL); if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat("HTML Format"); if (format != 0) hClip = SetClipboardData(format, NULL); } #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) hClip = SetClipboardData(CF_HDROP, NULL); #endif /** @todo Implement more flexible clipboard precedence for supported formats. */ if (hClip == NULL) LogRel(("Clipboard: Unsupported format(s) from host (0x%x), ignoring\n", fFormats)); VBoxClipboardWinClose(); LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: hClip=%p, lastErr=%ld\n", hClip, GetLastError())); } } break; case VBOX_CLIPBOARD_WM_READ_DATA: { /* Send data in the specified format to the host. */ uint32_t u32Formats = (uint32_t)lParam; HANDLE hClip = NULL; LogFlowFunc(("VBOX_WM_SHCLPB_READ_DATA: u32Formats=0x%x\n", u32Formats)); int vboxrc = VBoxClipboardWinOpen(hwnd); if (RT_SUCCESS(vboxrc)) { if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { hClip = GetClipboardData(CF_DIB); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { hClip = GetClipboardData(CF_UNICODETEXT); if (hClip != NULL) { LPWSTR uniString = (LPWSTR)GlobalLock(hClip); if (uniString != NULL) { vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat("HTML Format"); if (format != 0) { hClip = GetClipboardData(format); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } } #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) { hClip = GetClipboardData(CF_HDROP); if (hClip) { HDROP hDrop = (HDROP)GlobalLock(hClip); if (hDrop) { /* vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_URI_LIST, );*/ GlobalUnlock(hClip); } else { hClip = NULL; } } } #endif VBoxClipboardWinClose(); } if (hClip == NULL) { /* Requested clipboard format is not available, send empty data. */ VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0); } } break; case WM_DESTROY: { VBoxClipboardWinRemoveFromCBChain(pWinCtx); if (pWinCtx->oldAPI.timerRefresh) KillTimer(pWinCtx->hWnd, 0); /* * don't need to call PostQuitMessage cause * the VBoxTray already finished a message loop */ } break; default: { rc = DefWindowProc(hwnd, msg, wParam, lParam); } break; } #ifndef DEBUG_andy LogFlowFunc(("vboxClipboardProcessMsg returned with rc = %ld\n", rc)); #endif return rc; }
/** * Query if this objects supports a specific format. * * @return IPRT status code. * @return HRESULT * @param pFormatEtc */ STDMETHODIMP VBoxDnDDataObject::QueryGetData(FORMATETC *pFormatEtc) { LogFlowFunc(("\n")); return (LookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC; }
/** * Called by Qt's drag'n drop operation (QDrag) for retrieving the actual drag'n drop * data in case of a successful drag'n drop operation. * * @param strMIMEType MIME type string. * @param vaType Variant containing the actual data based on the the MIME type. * * @return QVariant */ QVariant UIDnDMIMEData::retrieveData(const QString &strMIMEType, QVariant::Type vaType) const { LogFlowFunc(("state=%RU32, curAction=0x%x, defAction=0x%x, mimeType=%s, type=%d (%s)\n", m_enmState, m_curAction, m_defAction, strMIMEType.toStdString().c_str(), vaType, QVariant::typeToName(vaType))); bool fCanDrop = true; /* Accept by default. */ #ifdef RT_OS_WINDOWS /* * On Windows this function will be called several times by Qt's * OLE-specific internals to figure out which data formats we have * to offer. So just assume we can drop data here for a start. */ #elif defined(RT_OS_DARWIN) /* * On OS X we rely on an internal flag which gets set in the overriden * hasFormat() function. That function only gets called on a successful drop * so that we can tell if we have to start receiving data the next time * we come by here. */ fCanDrop = m_fCanDrop; #else /* * On non-Windows our state gets updated via an own event filter * (see UIDnDMimeData::eventFilter). This filter will update the current * operation state for us (based on the mouse buttons). */ if (m_curAction == Qt::IgnoreAction) { LogFlowFunc(("Current drop action is 0x%x, so can't drop yet\n", m_curAction)); fCanDrop = false; } #endif if (fCanDrop) { /* Do we support the requested MIME type? */ if (!m_lstFormats.contains(strMIMEType)) { LogRel(("DnD: Unsupported MIME type '%s'\n", strMIMEType.toStdString().c_str())); fCanDrop = false; } /* Supported types. See below in the switch statement. */ if (!( /* Plain text. */ vaType == QVariant::String /* Binary data. */ || vaType == QVariant::ByteArray /* URI list. */ || vaType == QVariant::List)) { LogRel(("DnD: Unsupported data type '%s'\n", QVariant::typeToName(vaType))); fCanDrop = false; } } LogRel3(("DnD: State=%ld, Action=0x%x, fCanDrop=%RTbool\n", m_enmState, m_curAction, fCanDrop)); if (fCanDrop) { QVariant vaData; int rc = emit getData(strMIMEType, vaType, vaData); LogRel3(("DnD: Returning data of type=%s (requested MIME type=%s, requested type=%s), rc=%Rrc\n", vaData.typeName() ? vaData.typeName() : "<Invalid>", strMIMEType.toStdString().c_str(), QVariant::typeToName(vaType) ? QVariant::typeToName(vaType) : "<Invalid>", rc)); if (RT_SUCCESS(rc)) return vaData; } #ifdef RT_OS_DARWIN LogFlowFunc(("Returning data for Cocoa\n")); return QMimeData::retrieveData(strMIMEType, vaType); #else LogFlowFunc(("Skipping request, state=%RU32 ...\n", m_enmState)); return QVariant(QVariant::Invalid); /* Return a NULL variant. */ #endif }
int VBoxDnDDataObject::Abort(void) { LogFlowFunc(("Aborting ...\n")); mStatus = Aborted; return RTSemEventSignal(mSemEvent); }
/** * Initializes the guest object. */ HRESULT Guest::init(Console *aParent) { LogFlowThisFunc(("aParent=%p\n", aParent)); ComAssertRet(aParent, E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); unconst(mParent) = aParent; /* Confirm a successful initialization when it's the case */ autoInitSpan.setSucceeded(); ULONG aMemoryBalloonSize; HRESULT hr = mParent->i_machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize); if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ mMemoryBalloonSize = aMemoryBalloonSize; else mMemoryBalloonSize = 0; /* Default is no ballooning */ BOOL fPageFusionEnabled; hr = mParent->i_machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled); if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ mfPageFusionEnabled = fPageFusionEnabled; else mfPageFusionEnabled = false; /* Default is no page fusion*/ mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */ mCollectVMMStats = false; /* Clear statistics. */ mNetStatRx = mNetStatTx = 0; mNetStatLastTs = RTTimeNanoTS(); for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++) mCurrentGuestStat[i] = 0; mVmValidStats = pm::VMSTATMASK_NONE; RT_ZERO(mCurrentGuestCpuUserStat); RT_ZERO(mCurrentGuestCpuKernelStat); RT_ZERO(mCurrentGuestCpuIdleStat); mMagic = GUEST_MAGIC; int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */, &Guest::i_staticUpdateStats, this); AssertMsgRC(vrc, ("Failed to create guest statistics update timer (%Rrc)\n", vrc)); hr = unconst(mEventSource).createObject(); if (SUCCEEDED(hr)) hr = mEventSource->init(); mCpus = 1; #ifdef VBOX_WITH_DRAG_AND_DROP try { GuestDnD::createInstance(this /* pGuest */); hr = unconst(mDnDSource).createObject(); if (SUCCEEDED(hr)) hr = mDnDSource->init(this /* pGuest */); if (SUCCEEDED(hr)) { hr = unconst(mDnDTarget).createObject(); if (SUCCEEDED(hr)) hr = mDnDTarget->init(this /* pGuest */); } LogFlowFunc(("Drag and drop initializied with hr=%Rhrc\n", hr)); } catch (std::bad_alloc &) { hr = E_OUTOFMEMORY; } #endif LogFlowFunc(("hr=%Rhrc\n", hr)); return hr; }
int vboxClipboardUtf16LinToWin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest, size_t cwDest) { size_t i, j; LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc)); if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest)) { LogRel(("vboxClipboardUtf16LinToWin: received an invalid pointer, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest)); AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER); } if (cwSrc == 0) { if (cwDest == 0) { LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n")); return VERR_BUFFER_OVERFLOW; } pu16Dest[0] = 0; LogFlowFunc(("empty source string, returning\n")); return VINF_SUCCESS; } /* We only take little endian Utf16 */ if (pwszSrc[0] == UTF16BEMARKER) { LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n")); AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER); } /* Don't copy the endian marker. */ for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0), j = 0; i < cwSrc; ++i, ++j) { /* Don't copy the null byte, as we add it below. */ if (pwszSrc[i] == 0) break; if (j == cwDest) { LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n")); return VERR_BUFFER_OVERFLOW; } if (pwszSrc[i] == LINEFEED) { pu16Dest[j] = CARRIAGERETURN; ++j; if (j == cwDest) { LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n")); return VERR_BUFFER_OVERFLOW; } } #ifdef RT_OS_DARWIN /* Check for a single carriage return (MacOS) */ else if (pwszSrc[i] == CARRIAGERETURN) { /* set cr */ pu16Dest[j] = CARRIAGERETURN; ++j; if (j == cwDest) { LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n")); return VERR_BUFFER_OVERFLOW; } /* add the lf */ pu16Dest[j] = LINEFEED; continue; } #endif pu16Dest[j] = pwszSrc[i]; } /* Add the trailing null. */ if (j == cwDest) { LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n")); return VERR_BUFFER_OVERFLOW; } pu16Dest[j] = 0; LogFlowFunc(("rc=VINF_SUCCESS, pu16Dest=%ls\n", pu16Dest)); return VINF_SUCCESS; }