/* $Id: com.cpp 44563 2013-02-06 13:15:10Z vboxsync $ */ /** @file * MS COM / XPCOM Abstraction Layer */ /* * Copyright (C) 2005-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #if !defined (VBOX_WITH_XPCOM) # include #else /* !defined (VBOX_WITH_XPCOM) */ # include # include # include # include # include # include # include # include # include // official XPCOM headers don't define it yet #define IPC_DCONNECTSERVICE_CONTRACTID \ "@mozilla.org/ipc/dconnect-service;1" #endif /* !defined (VBOX_WITH_XPCOM) */ #include "VBox/com/com.h" #include "VBox/com/assert.h" #include "VBox/com/Guid.h" #include "VBox/com/array.h" #include #include #include #include #include #include #include #include #include #include #include #if !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS) char szXdgConfigHome[RTPATH_MAX] = ""; #endif /** * Possible locations for the VirtualBox user configuration folder, * listed from oldest (as in legacy) to newest. These can be either * absolute or relative to the home directory. We use the first entry * of the list which corresponds to a real folder on storage, or * create a folder corresponding to the last in the list (the least * legacy) if none do. */ const char *const apcszUserHome[] = #ifdef RT_OS_DARWIN { "Library/VirtualBox" }; #elif defined RT_OS_WINDOWS { ".VirtualBox" }; #else { ".VirtualBox", szXdgConfigHome }; #endif #include "Logging.h" namespace com { void GetInterfaceNameByIID(const GUID &aIID, BSTR *aName) { Assert(aName); if (!aName) return; *aName = NULL; #if !defined(VBOX_WITH_XPCOM) LONG rc; LPOLESTR iidStr = NULL; if (StringFromIID(aIID, &iidStr) == S_OK) { HKEY ifaceKey; rc = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Interface", 0, KEY_QUERY_VALUE, &ifaceKey); if (rc == ERROR_SUCCESS) { HKEY iidKey; rc = RegOpenKeyExW(ifaceKey, iidStr, 0, KEY_QUERY_VALUE, &iidKey); if (rc == ERROR_SUCCESS) { /* determine the size and type */ DWORD sz, type; rc = RegQueryValueExW(iidKey, NULL, NULL, &type, NULL, &sz); if (rc == ERROR_SUCCESS && type == REG_SZ) { /* query the value to BSTR */ *aName = SysAllocStringLen(NULL, (sz + 1) / sizeof(TCHAR) + 1); rc = RegQueryValueExW(iidKey, NULL, NULL, NULL, (LPBYTE) *aName, &sz); if (rc != ERROR_SUCCESS) { SysFreeString(*aName); aName = NULL; } } RegCloseKey(iidKey); } RegCloseKey(ifaceKey); } CoTaskMemFree(iidStr); } #else /* !defined (VBOX_WITH_XPCOM) */ nsresult rv; nsCOMPtr iim = do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { nsCOMPtr iinfo; rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); if (NS_SUCCEEDED(rv)) { const char *iname = NULL; iinfo->GetNameShared(&iname); char *utf8IName = NULL; if (RT_SUCCESS(RTStrCurrentCPToUtf8(&utf8IName, iname))) { PRTUTF16 utf16IName = NULL; if (RT_SUCCESS(RTStrToUtf16(utf8IName, &utf16IName))) { *aName = SysAllocString((OLECHAR *) utf16IName); RTUtf16Free(utf16IName); } RTStrFree(utf8IName); } } } #endif /* !defined (VBOX_WITH_XPCOM) */ } #ifdef VBOX_WITH_XPCOM HRESULT GlueCreateObjectOnServer(const CLSID &clsid, const char *serverName, const nsIID &id, void** ppobj) { HRESULT rc; nsCOMPtr ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc); if (SUCCEEDED(rc)) { PRUint32 serverID = 0; rc = ipcServ->ResolveClientName(serverName, &serverID); if (SUCCEEDED (rc)) { nsCOMPtr dconServ = do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc); if (SUCCEEDED(rc)) rc = dconServ->CreateInstance(serverID, clsid, id, ppobj); } } return rc; } HRESULT GlueCreateInstance(const CLSID &clsid, const nsIID &id, void** ppobj) { nsCOMPtr manager; HRESULT rc = NS_GetComponentManager(getter_AddRefs(manager)); if (SUCCEEDED(rc)) rc = manager->CreateInstance(clsid, nsnull, id, ppobj); return rc; } #endif // VBOX_WITH_XPCOM static int composeHomePath(char *aDir, size_t aDirLen, const char *pcszBase) { int vrc; if (RTPathStartsWithRoot(pcszBase)) vrc = RTStrCopy(aDir, aDirLen, pcszBase); else { /* compose the config directory (full path) */ /** @todo r=bird: RTPathUserHome doesn't necessarily return a * full (abs) path like the comment above seems to indicate. */ vrc = RTPathUserHome(aDir, aDirLen); if (RT_SUCCESS(vrc)) vrc = RTPathAppend(aDir, aDirLen, pcszBase); } return vrc; } int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir) { AssertReturn(aDir, VERR_INVALID_POINTER); AssertReturn(aDirLen > 0, VERR_BUFFER_OVERFLOW); /* start with null */ *aDir = 0; char szTmp[RTPATH_MAX]; int vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_USER_HOME", szTmp, sizeof(szTmp), NULL); if (RT_SUCCESS(vrc) || vrc == VERR_ENV_VAR_NOT_FOUND) { bool fFound = false; if (RT_SUCCESS(vrc)) { /* get the full path name */ vrc = RTPathAbs(szTmp, aDir, aDirLen); } else { #if !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN) const char *pcszConfigHome = RTEnvGet("XDG_CONFIG_HOME"); if (pcszConfigHome && pcszConfigHome[0]) { vrc = RTStrCopy(szXdgConfigHome, sizeof(szXdgConfigHome), pcszConfigHome); if (RT_SUCCESS(vrc)) vrc = RTPathAppend(szXdgConfigHome, sizeof(szXdgConfigHome), "VirtualBox"); } else vrc = RTStrCopy(szXdgConfigHome, sizeof(szXdgConfigHome), ".config/VirtualBox"); #endif for (unsigned i = 0; i < RT_ELEMENTS(apcszUserHome); ++i) { vrc = composeHomePath(aDir, aDirLen, apcszUserHome[i]); if (RTDirExists(aDir)) { fFound = true; break; } } } /* ensure the home directory exists */ if (RT_SUCCESS(vrc)) if (!fFound && fCreateDir) vrc = RTDirCreateFullPath(aDir, 0700); } return vrc; } static const char *g_pszLogEntity = NULL; static void vboxHeaderFooter(PRTLOGGER pReleaseLogger, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog) { /* some introductory information */ static RTTIMESPEC s_TimeSpec; char szTmp[256]; if (enmPhase == RTLOGPHASE_BEGIN) RTTimeNow(&s_TimeSpec); RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp)); switch (enmPhase) { case RTLOGPHASE_BEGIN: { bool fOldBuffered = RTLogSetBuffering(pReleaseLogger, true /*fBuffered*/); pfnLog(pReleaseLogger, "VirtualBox %s %s r%u %s (%s %s) release log\n" #ifdef VBOX_BLEEDING_EDGE "EXPERIMENTAL build " VBOX_BLEEDING_EDGE "\n" #endif "Log opened %s\n", g_pszLogEntity, VBOX_VERSION_STRING, RTBldCfgRevision(), RTBldCfgTargetDotArch(), __DATE__, __TIME__, szTmp); int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "OS Product: %s\n", szTmp); vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "OS Release: %s\n", szTmp); vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "OS Version: %s\n", szTmp); vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "OS Service Pack: %s\n", szTmp); vrc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "DMI Product Name: %s\n", szTmp); vrc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_VERSION, szTmp, sizeof(szTmp)); if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW) pfnLog(pReleaseLogger, "DMI Product Version: %s\n", szTmp); uint64_t cbHostRam = 0, cbHostRamAvail = 0; vrc = RTSystemQueryTotalRam(&cbHostRam); if (RT_SUCCESS(vrc)) vrc = RTSystemQueryAvailableRam(&cbHostRamAvail); if (RT_SUCCESS(vrc)) pfnLog(pReleaseLogger, "Host RAM: %lluMB total, %lluMB available\n", cbHostRam / _1M, cbHostRamAvail / _1M); /* the package type is interesting for Linux distributions */ char szExecName[RTPATH_MAX]; char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName)); pfnLog(pReleaseLogger, "Executable: %s\n" "Process ID: %u\n" "Package type: %s" #ifdef VBOX_OSE " (OSE)" #endif "\n", pszExecName ? pszExecName : "unknown", RTProcSelf(), VBOX_PACKAGE_STRING); RTLogSetBuffering(pReleaseLogger, fOldBuffered); break; } case RTLOGPHASE_PREROTATE: pfnLog(pReleaseLogger, "Log rotated - Log started %s\n", szTmp); break; case RTLOGPHASE_POSTROTATE: pfnLog(pReleaseLogger, "Log continuation - Log started %s\n", szTmp); break; case RTLOGPHASE_END: pfnLog(pReleaseLogger, "End of log file - Log started %s\n", szTmp); break; default: /* nothing */; } } int VBoxLogRelCreate(const char *pcszEntity, const char *pcszLogFile, uint32_t fFlags, const char *pcszGroupSettings, const char *pcszEnvVarBase, uint32_t fDestFlags, uint32_t cMaxEntriesPerGroup, uint32_t cHistory, uint32_t uHistoryFileTime, uint64_t uHistoryFileSize, char *pszError, size_t cbError) { Assert(cbError >= RTPATH_MAX + 128); /* create release logger */ PRTLOGGER pReleaseLogger; static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) fFlags |= RTLOGFLAGS_USECRLF; #endif g_pszLogEntity = pcszEntity; int vrc = RTLogCreateEx(&pReleaseLogger, fFlags, pcszGroupSettings, pcszEnvVarBase, RT_ELEMENTS(s_apszGroups), s_apszGroups, fDestFlags, vboxHeaderFooter, cHistory, uHistoryFileSize, uHistoryFileTime, pszError, cbError, pcszLogFile); if (RT_SUCCESS(vrc)) { /* make sure that we don't flood logfiles */ RTLogSetGroupLimit(pReleaseLogger, cMaxEntriesPerGroup); /* explicitly flush the log, to have some info when buffering */ RTLogFlush(pReleaseLogger); /* register this logger as the release logger */ RTLogRelSetDefaultInstance(pReleaseLogger); } return vrc; } /* static */ const Guid Guid::Empty; /* default ctor is OK */ #if defined (VBOX_WITH_XPCOM) /* static */ const nsID *SafeGUIDArray::nsIDRef::Empty = (const nsID *)Guid::Empty.raw(); #endif /* (VBOX_WITH_XPCOM) */ /** * Used by ComPtr and friends to log details about reference counting. * @param pcszFormat */ void LogRef(const char *pcszFormat, ...) { char *pszNewMsg; va_list args; va_start(args, pcszFormat); RTStrAPrintfV(&pszNewMsg, pcszFormat, args); LogDJ((pszNewMsg)); RTStrFree(pszNewMsg); va_end(args); } } /* namespace com */