aboutsummaryrefslogtreecommitdiff
path: root/src/win32/WIN32Util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32/WIN32Util.cpp')
-rw-r--r--src/win32/WIN32Util.cpp1600
1 files changed, 1600 insertions, 0 deletions
diff --git a/src/win32/WIN32Util.cpp b/src/win32/WIN32Util.cpp
new file mode 100644
index 0000000000..9697fc784c
--- /dev/null
+++ b/src/win32/WIN32Util.cpp
@@ -0,0 +1,1600 @@
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "WIN32Util.h"
+#include "Util.h"
+#include "utils/URIUtils.h"
+#include "storage/cdioSupport.h"
+#include "PowrProf.h"
+#include "WindowHelper.h"
+#include "Application.h"
+#include <shlobj.h>
+#include "filesystem/SpecialProtocol.h"
+#include "my_ntddscsi.h"
+#include "Setupapi.h"
+#include "storage/MediaManager.h"
+#include "windowing/WindowingFactory.h"
+#include "guilib/LocalizeStrings.h"
+#include "utils/CharsetConverter.h"
+#include "utils/log.h"
+#include "DllPaths_win32.h"
+#include "FileSystem/File.h"
+#include "utils/URIUtils.h"
+#include "powermanagement\PowerManager.h"
+#include "utils/SystemInfo.h"
+#include "utils/Environment.h"
+#include "utils/URIUtils.h"
+#include "utils/StringUtils.h"
+
+#define DLL_ENV_PATH "special://xbmc/system/;" \
+ "special://xbmc/system/players/dvdplayer/;" \
+ "special://xbmc/system/players/paplayer/;" \
+ "special://xbmc/system/cdrip/;" \
+ "special://xbmc/system/python/;" \
+ "special://xbmc/system/webserver/;" \
+ "special://xbmc/"
+
+extern HWND g_hWnd;
+
+using namespace std;
+using namespace MEDIA_DETECT;
+
+CWIN32Util::CWIN32Util(void)
+{
+}
+
+CWIN32Util::~CWIN32Util(void)
+{
+}
+
+int CWIN32Util::GetDriveStatus(const std::string &strPath, bool bStatusEx)
+{
+ HANDLE hDevice; // handle to the drive to be examined
+ int iResult; // results flag
+ ULONG ulChanges=0;
+ DWORD dwBytesReturned;
+ T_SPDT_SBUF sptd_sb; //SCSI Pass Through Direct variable.
+ byte DataBuf[8]; //Buffer for holding data to/from drive.
+
+ CLog::Log(LOGDEBUG, __FUNCTION__": Requesting status for drive %s.", strPath.c_str());
+
+ hDevice = CreateFile( strPath.c_str(), // drive
+ 0, // no access to the drive
+ FILE_SHARE_READ, // share mode
+ NULL, // default security attributes
+ OPEN_EXISTING, // disposition
+ FILE_ATTRIBUTE_READONLY, // file attributes
+ NULL);
+
+ if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to CreateFile for %s.", strPath.c_str());
+ return -1;
+ }
+
+ CLog::Log(LOGDEBUG, __FUNCTION__": Requesting media status for drive %s.", strPath.c_str());
+ iResult = DeviceIoControl((HANDLE) hDevice, // handle to device
+ IOCTL_STORAGE_CHECK_VERIFY2, // dwIoControlCode
+ NULL, // lpInBuffer
+ 0, // nInBufferSize
+ &ulChanges, // lpOutBuffer
+ sizeof(ULONG), // nOutBufferSize
+ &dwBytesReturned , // number of bytes returned
+ NULL ); // OVERLAPPED structure
+
+ CloseHandle(hDevice);
+
+ if(iResult == 1)
+ return 2;
+
+ // don't request the tray status as we often doesn't need it
+ if(!bStatusEx)
+ return 0;
+
+ hDevice = CreateFile( strPath.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_READONLY,
+ NULL);
+
+ if (hDevice == INVALID_HANDLE_VALUE)
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to CreateFile2 for %s.", strPath.c_str());
+ return -1;
+ }
+
+ sptd_sb.sptd.Length=sizeof(SCSI_PASS_THROUGH_DIRECT);
+ sptd_sb.sptd.PathId=0;
+ sptd_sb.sptd.TargetId=0;
+ sptd_sb.sptd.Lun=0;
+ sptd_sb.sptd.CdbLength=10;
+ sptd_sb.sptd.SenseInfoLength=MAX_SENSE_LEN;
+ sptd_sb.sptd.DataIn=SCSI_IOCTL_DATA_IN;
+ sptd_sb.sptd.DataTransferLength=sizeof(DataBuf);
+ sptd_sb.sptd.TimeOutValue=2;
+ sptd_sb.sptd.DataBuffer=(PVOID)&(DataBuf);
+ sptd_sb.sptd.SenseInfoOffset=sizeof(SCSI_PASS_THROUGH_DIRECT);
+
+ sptd_sb.sptd.Cdb[0]=0x4a;
+ sptd_sb.sptd.Cdb[1]=1;
+ sptd_sb.sptd.Cdb[2]=0;
+ sptd_sb.sptd.Cdb[3]=0;
+ sptd_sb.sptd.Cdb[4]=0x10;
+ sptd_sb.sptd.Cdb[5]=0;
+ sptd_sb.sptd.Cdb[6]=0;
+ sptd_sb.sptd.Cdb[7]=0;
+ sptd_sb.sptd.Cdb[8]=8;
+ sptd_sb.sptd.Cdb[9]=0;
+ sptd_sb.sptd.Cdb[10]=0;
+ sptd_sb.sptd.Cdb[11]=0;
+ sptd_sb.sptd.Cdb[12]=0;
+ sptd_sb.sptd.Cdb[13]=0;
+ sptd_sb.sptd.Cdb[14]=0;
+ sptd_sb.sptd.Cdb[15]=0;
+
+ ZeroMemory(DataBuf, 8);
+ ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN);
+
+ //Send the command to drive
+ CLog::Log(LOGDEBUG, __FUNCTION__": Requesting tray status for drive %s.", strPath.c_str());
+ iResult = DeviceIoControl((HANDLE) hDevice,
+ IOCTL_SCSI_PASS_THROUGH_DIRECT,
+ (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb),
+ (PVOID)&sptd_sb, (DWORD)sizeof(sptd_sb),
+ &dwBytesReturned,
+ NULL);
+
+ CloseHandle(hDevice);
+
+ if(iResult)
+ {
+
+ if(DataBuf[5] == 0) // tray close
+ return 0;
+ else if(DataBuf[5] == 1) // tray open
+ return 1;
+ else
+ return 2; // tray closed, media present
+ }
+ CLog::Log(LOGERROR, __FUNCTION__": Could not determine tray status %d", GetLastError());
+ return -1;
+}
+
+char CWIN32Util::FirstDriveFromMask (ULONG unitmask)
+{
+ char i;
+ for (i = 0; i < 26; ++i)
+ {
+ if (unitmask & 0x1) break;
+ unitmask = unitmask >> 1;
+ }
+ return (i + 'A');
+}
+
+bool CWIN32Util::PowerManagement(PowerState State)
+{
+ static bool gotShutdownPrivileges = false;
+ if (!gotShutdownPrivileges)
+ {
+ HANDLE hToken;
+ // Get a token for this process.
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ {
+ // Get the LUID for the shutdown privilege.
+ TOKEN_PRIVILEGES tkp = {};
+ if (LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid))
+ {
+ tkp.PrivilegeCount = 1; // one privilege to set
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ // Get the shutdown privilege for this process.
+ if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
+ gotShutdownPrivileges = true;
+ }
+ CloseHandle(hToken);
+ }
+
+ if (!gotShutdownPrivileges)
+ return false;
+ }
+
+ // process OnSleep() events. This is called in main thread.
+ g_powerManager.ProcessEvents();
+
+ switch (State)
+ {
+ case POWERSTATE_HIBERNATE:
+ CLog::Log(LOGINFO, "Asking Windows to hibernate...");
+ return SetSuspendState(true,true,false) == TRUE;
+ break;
+ case POWERSTATE_SUSPEND:
+ CLog::Log(LOGINFO, "Asking Windows to suspend...");
+ return SetSuspendState(false,true,false) == TRUE;
+ break;
+ case POWERSTATE_SHUTDOWN:
+ CLog::Log(LOGINFO, "Shutdown Windows...");
+ if (g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin8))
+ return InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_HYBRID | SHUTDOWN_INSTALL_UPDATES | SHUTDOWN_POWEROFF,
+ SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED) == ERROR_SUCCESS;
+ return InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_INSTALL_UPDATES | SHUTDOWN_POWEROFF,
+ SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED) == ERROR_SUCCESS;
+ break;
+ case POWERSTATE_REBOOT:
+ CLog::Log(LOGINFO, "Rebooting Windows...");
+ if (g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin8))
+ return InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_INSTALL_UPDATES | SHUTDOWN_RESTART,
+ SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED) == ERROR_SUCCESS;
+ return InitiateShutdownW(NULL, NULL, 0, SHUTDOWN_INSTALL_UPDATES | SHUTDOWN_RESTART,
+ SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED) == ERROR_SUCCESS;
+ break;
+ default:
+ CLog::Log(LOGERROR, "Unknown PowerState called.");
+ return false;
+ break;
+ }
+}
+
+int CWIN32Util::BatteryLevel()
+{
+ SYSTEM_POWER_STATUS SystemPowerStatus;
+
+ if (GetSystemPowerStatus(&SystemPowerStatus) && SystemPowerStatus.BatteryLifePercent != 255)
+ return SystemPowerStatus.BatteryLifePercent;
+
+ return 0;
+}
+
+bool CWIN32Util::XBMCShellExecute(const std::string &strPath, bool bWaitForScriptExit)
+{
+ std::string strCommand = strPath;
+ std::string strExe = strPath;
+ std::string strParams;
+ std::string strWorkingDir;
+
+ StringUtils::Trim(strCommand);
+ if (strCommand.empty())
+ {
+ return false;
+ }
+ size_t iIndex = std::string::npos;
+ char split = ' ';
+ if (strCommand[0] == '\"')
+ {
+ split = '\"';
+ }
+ iIndex = strCommand.find(split, 1);
+ if (iIndex != std::string::npos)
+ {
+ strExe = strCommand.substr(0, iIndex + 1);
+ strParams = strCommand.substr(iIndex + 1);
+ }
+
+ StringUtils::Replace(strExe, "\"", "");
+
+ strWorkingDir = strExe;
+ iIndex = strWorkingDir.rfind('\\');
+ if(iIndex != std::string::npos)
+ {
+ strWorkingDir[iIndex+1] = '\0';
+ }
+
+ std::wstring WstrExe, WstrParams, WstrWorkingDir;
+ g_charsetConverter.utf8ToW(strExe, WstrExe);
+ g_charsetConverter.utf8ToW(strParams, WstrParams);
+ g_charsetConverter.utf8ToW(strWorkingDir, WstrWorkingDir);
+
+ bool ret;
+ SHELLEXECUTEINFOW ShExecInfo = {0};
+ ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+ ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+ ShExecInfo.hwnd = NULL;
+ ShExecInfo.lpVerb = NULL;
+ ShExecInfo.lpFile = WstrExe.c_str();
+ ShExecInfo.lpParameters = WstrParams.c_str();
+ ShExecInfo.lpDirectory = WstrWorkingDir.c_str();
+ ShExecInfo.nShow = SW_SHOW;
+ ShExecInfo.hInstApp = NULL;
+
+ g_windowHelper.StopThread();
+
+ LockSetForegroundWindow(LSFW_UNLOCK);
+ ShowWindow(g_hWnd,SW_MINIMIZE);
+ ret = ShellExecuteExW(&ShExecInfo) == TRUE;
+ g_windowHelper.SetHANDLE(ShExecInfo.hProcess);
+
+ // ShellExecute doesn't return the window of the started process
+ // we need to gather it from somewhere to allow switch back to XBMC
+ // when a program is minimized instead of stopped.
+ //g_windowHelper.SetHWND(ShExecInfo.hwnd);
+ g_windowHelper.Create();
+
+ if(bWaitForScriptExit)
+ {
+ // Todo: Pause music and video playback
+ WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
+ }
+
+ return ret;
+}
+
+std::vector<std::string> CWIN32Util::GetDiskUsage()
+{
+ vector<std::string> result;
+ ULARGE_INTEGER ULTotal= { { 0 } };
+ ULARGE_INTEGER ULTotalFree= { { 0 } };
+
+ char* pcBuffer= NULL;
+ DWORD dwStrLength= GetLogicalDriveStrings( 0, pcBuffer );
+ if( dwStrLength != 0 )
+ {
+ std::string strRet;
+
+ dwStrLength+= 1;
+ pcBuffer= new char [dwStrLength];
+ GetLogicalDriveStrings( dwStrLength, pcBuffer );
+ int iPos= 0;
+ do
+ {
+ std::string strDrive = pcBuffer + iPos;
+ if( DRIVE_FIXED == GetDriveType( strDrive.c_str() ) &&
+ GetDiskFreeSpaceEx( ( strDrive.c_str() ), NULL, &ULTotal, &ULTotalFree ) )
+ {
+ strRet = StringUtils::Format("%s %d MB %s",strDrive.c_str(), int(ULTotalFree.QuadPart/(1024*1024)),g_localizeStrings.Get(160).c_str());
+ result.push_back(strRet);
+ }
+ iPos += (strlen( pcBuffer + iPos) + 1 );
+ }while( strlen( pcBuffer + iPos ) > 0 );
+ }
+ delete[] pcBuffer;
+ return result;
+}
+
+std::string CWIN32Util::GetResInfoString()
+{
+ DEVMODE devmode;
+ ZeroMemory(&devmode, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ return StringUtils::Format("Desktop Resolution: %dx%d %dBit at %dHz",devmode.dmPelsWidth,devmode.dmPelsHeight,devmode.dmBitsPerPel,devmode.dmDisplayFrequency);
+}
+
+int CWIN32Util::GetDesktopColorDepth()
+{
+ DEVMODE devmode;
+ ZeroMemory(&devmode, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ return (int)devmode.dmBitsPerPel;
+}
+
+std::string CWIN32Util::GetSpecialFolder(int csidl)
+{
+ std::string strProfilePath;
+ static const int bufSize = MAX_PATH;
+ WCHAR* buf = new WCHAR[bufSize];
+
+ if(SUCCEEDED(SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, buf)))
+ {
+ buf[bufSize-1] = 0;
+ g_charsetConverter.wToUTF8(buf, strProfilePath);
+ strProfilePath = UncToSmb(strProfilePath);
+ }
+ else
+ strProfilePath = "";
+
+ delete[] buf;
+ return strProfilePath;
+}
+
+std::string CWIN32Util::GetSystemPath()
+{
+ return GetSpecialFolder(CSIDL_SYSTEM);
+}
+
+std::string CWIN32Util::GetProfilePath()
+{
+ std::string strProfilePath;
+ CStdString strHomePath;
+
+ CUtil::GetHomePath(strHomePath);
+
+ if(g_application.PlatformDirectoriesEnabled())
+ strProfilePath = URIUtils::AddFileToFolder(GetSpecialFolder(CSIDL_APPDATA|CSIDL_FLAG_CREATE), "Kodi");
+ else
+ strProfilePath = URIUtils::AddFileToFolder(strHomePath , "portable_data");
+
+ if (strProfilePath.length() == 0)
+ strProfilePath = strHomePath;
+
+ URIUtils::AddSlashAtEnd(strProfilePath);
+
+ return strProfilePath;
+}
+
+std::string CWIN32Util::UncToSmb(const std::string &strPath)
+{
+ std::string strRetPath(strPath);
+ if(StringUtils::StartsWith(strRetPath, "\\\\"))
+ {
+ strRetPath = "smb:" + strPath;
+ StringUtils::Replace(strRetPath, '\\', '/');
+ }
+ return strRetPath;
+}
+
+std::string CWIN32Util::SmbToUnc(const std::string &strPath)
+{
+ std::string strRetPath(strPath);
+ if(StringUtils::StartsWithNoCase(strRetPath, "smb://"))
+ {
+ StringUtils::Replace(strRetPath, "smb://", "\\\\");
+ StringUtils::Replace(strRetPath, '/', '\\');
+ }
+ return strRetPath;
+}
+
+bool CWIN32Util::AddExtraLongPathPrefix(std::wstring& path)
+{
+ const wchar_t* const str = path.c_str();
+ if (path.length() < 4 || str[0] != L'\\' || str[1] != L'\\' || str[3] != L'\\' || str[2] != L'?')
+ {
+ path.insert(0, L"\\\\?\\");
+ return true;
+ }
+ return false;
+}
+
+bool CWIN32Util::RemoveExtraLongPathPrefix(std::wstring& path)
+{
+ const wchar_t* const str = path.c_str();
+ if (path.length() >= 4 && str[0] == L'\\' && str[1] == L'\\' && str[3] == L'\\' && str[2] == L'?')
+ {
+ path.erase(0, 4);
+ return true;
+ }
+ return false;
+}
+
+std::wstring CWIN32Util::ConvertPathToWin32Form(const std::string& pathUtf8)
+{
+ std::wstring result;
+ if (pathUtf8.empty())
+ return result;
+
+ bool convertResult;
+
+ if (pathUtf8.compare(0, 2, "\\\\", 2) != 0) // pathUtf8 don't start from "\\"
+ { // assume local file path in form 'C:\Folder\File.ext'
+ std::string formedPath("\\\\?\\"); // insert "\\?\" prefix
+ formedPath += URIUtils::CanonicalizePath(URIUtils::FixSlashesAndDups(pathUtf8, '\\'), '\\'); // fix duplicated and forward slashes, resolve relative path
+ convertResult = g_charsetConverter.utf8ToW(formedPath, result, false, false, true);
+ }
+ else if (pathUtf8.compare(0, 8, "\\\\?\\UNC\\", 8) == 0) // pathUtf8 starts from "\\?\UNC\"
+ {
+ std::string formedPath("\\\\?\\UNC"); // start from "\\?\UNC" prefix
+ formedPath += URIUtils::CanonicalizePath(URIUtils::FixSlashesAndDups(pathUtf8.substr(7), '\\'), '\\'); // fix duplicated and forward slashes, resolve relative path, don't touch "\\?\UNC" prefix,
+ convertResult = g_charsetConverter.utf8ToW(formedPath, result, false, false, true);
+ }
+ else if (pathUtf8.compare(0, 4, "\\\\?\\", 4) == 0) // pathUtf8 starts from "\\?\", but it's not UNC path
+ {
+ std::string formedPath("\\\\?"); // start from "\\?" prefix
+ formedPath += URIUtils::CanonicalizePath(URIUtils::FixSlashesAndDups(pathUtf8.substr(3), '\\'), '\\'); // fix duplicated and forward slashes, resolve relative path, don't touch "\\?" prefix,
+ convertResult = g_charsetConverter.utf8ToW(formedPath, result, false, false, true);
+ }
+ else // pathUtf8 starts from "\\", but not from "\\?\UNC\"
+ { // assume UNC path in form '\\server\share\folder\file.ext'
+ std::string formedPath("\\\\?\\UNC"); // append "\\?\UNC" prefix
+ formedPath += URIUtils::CanonicalizePath(URIUtils::FixSlashesAndDups(pathUtf8), '\\'); // fix duplicated and forward slashes, resolve relative path, transform "\\" prefix to single "\"
+ convertResult = g_charsetConverter.utf8ToW(formedPath, result, false, false, true);
+ }
+
+ if (!convertResult)
+ {
+ CLog::Log(LOGERROR, "Error converting path \"%s\" to Win32 wide string!", pathUtf8.c_str());
+ return L"";
+ }
+
+ return result;
+}
+
+std::wstring CWIN32Util::ConvertPathToWin32Form(const CURL& url)
+{
+ assert(url.GetProtocol().empty() || url.IsProtocol("smb"));
+
+ if (url.GetFileName().empty())
+ return std::wstring(); // empty string
+
+ if (url.GetProtocol().empty())
+ {
+ std::wstring result;
+ if (g_charsetConverter.utf8ToW("\\\\?\\" +
+ URIUtils::CanonicalizePath(URIUtils::FixSlashesAndDups(url.GetFileName(), '\\'), '\\'), result, false, false, true))
+ return result;
+ }
+ else if (url.IsProtocol("smb"))
+ {
+ if (url.GetHostName().empty())
+ return std::wstring(); // empty string
+
+ std::wstring result;
+ if (g_charsetConverter.utf8ToW("\\\\?\\UNC\\" +
+ URIUtils::CanonicalizePath(URIUtils::FixSlashesAndDups(url.GetHostName() + '\\' + url.GetFileName(), '\\'), '\\'),
+ result, false, false, true))
+ return result;
+ }
+ else
+ return std::wstring(); // unsupported protocol, return empty string
+
+ CLog::Log(LOGERROR, "%s: Error converting path \"%s\" to Win32 form", __FUNCTION__, url.Get().c_str());
+ return std::wstring(); // empty string
+}
+
+__time64_t CWIN32Util::fileTimeToTimeT(const FILETIME& ftimeft)
+{
+ if (!ftimeft.dwHighDateTime && !ftimeft.dwLowDateTime)
+ return 0;
+
+ return fileTimeToTimeT((__int64(ftimeft.dwHighDateTime) << 32) + __int64(ftimeft.dwLowDateTime));
+}
+
+__time64_t CWIN32Util::fileTimeToTimeT(const LARGE_INTEGER& ftimeli)
+{
+ if (ftimeli.QuadPart == 0)
+ return 0;
+
+ return fileTimeToTimeT(__int64(ftimeli.QuadPart));
+}
+
+
+void CWIN32Util::ExtendDllPath()
+{
+ std::string strEnv;
+ std::vector<std::string> vecEnv;
+ strEnv = CEnvironment::getenv("PATH");
+ if (strEnv.empty())
+ CLog::Log(LOGWARNING, "Can get system env PATH or PATH is empty");
+
+ vecEnv = StringUtils::Split(DLL_ENV_PATH, ";");
+ for (int i=0; i<(int)vecEnv.size(); ++i)
+ strEnv.append(";" + CSpecialProtocol::TranslatePath(vecEnv[i]));
+
+ if (CEnvironment::setenv("PATH", strEnv) == 0)
+ CLog::Log(LOGDEBUG,"Setting system env PATH to %s",strEnv.c_str());
+ else
+ CLog::Log(LOGDEBUG,"Can't set system env PATH to %s",strEnv.c_str());
+
+}
+
+HRESULT CWIN32Util::ToggleTray(const char cDriveLetter)
+{
+ BOOL bRet= FALSE;
+ DWORD dwReq = 0;
+ char cDL = cDriveLetter;
+ if( !cDL )
+ {
+ std::string dvdDevice = g_mediaManager.TranslateDevicePath("");
+ if(dvdDevice == "")
+ return S_FALSE;
+ cDL = dvdDevice[0];
+ }
+
+ std::string strVolFormat = StringUtils::Format("\\\\.\\%c:", cDL);
+ HANDLE hDrive= CreateFile( strVolFormat.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ std::string strRootFormat = StringUtils::Format("%c:\\", cDL);
+ if( ( hDrive != INVALID_HANDLE_VALUE || GetLastError() == NO_ERROR) &&
+ ( GetDriveType( strRootFormat.c_str() ) == DRIVE_CDROM ) )
+ {
+ DWORD dwDummy;
+ dwReq = (GetDriveStatus(strVolFormat, true) == 1) ? IOCTL_STORAGE_LOAD_MEDIA : IOCTL_STORAGE_EJECT_MEDIA;
+ bRet = DeviceIoControl( hDrive, dwReq, NULL, 0, NULL, 0, &dwDummy, NULL);
+ CloseHandle( hDrive );
+ }
+ // Windows doesn't seem to send always DBT_DEVICEREMOVECOMPLETE
+ // unmount it here too as it won't hurt
+ if(dwReq == IOCTL_STORAGE_EJECT_MEDIA && bRet == 1)
+ {
+ strRootFormat = StringUtils::Format("%c:", cDL);
+ CMediaSource share;
+ share.strPath = strRootFormat;
+ share.strName = share.strPath;
+ g_mediaManager.RemoveAutoSource(share);
+ }
+ return bRet? S_OK : S_FALSE;
+}
+
+HRESULT CWIN32Util::EjectTray(const char cDriveLetter)
+{
+ char cDL = cDriveLetter;
+ if( !cDL )
+ {
+ std::string dvdDevice = g_mediaManager.TranslateDevicePath("");
+ if(dvdDevice.empty())
+ return S_FALSE;
+ cDL = dvdDevice[0];
+ }
+
+ std::string strVolFormat = StringUtils::Format("\\\\.\\%c:", cDL);
+
+ if(GetDriveStatus(strVolFormat, true) != 1)
+ return ToggleTray(cDL);
+ else
+ return S_OK;
+}
+
+HRESULT CWIN32Util::CloseTray(const char cDriveLetter)
+{
+ char cDL = cDriveLetter;
+ if( !cDL )
+ {
+ std::string dvdDevice = g_mediaManager.TranslateDevicePath("");
+ if(dvdDevice.empty())
+ return S_FALSE;
+ cDL = dvdDevice[0];
+ }
+
+ std::string strVolFormat = StringUtils::Format( "\\\\.\\%c:", cDL);
+
+ if(GetDriveStatus(strVolFormat, true) == 1)
+ return ToggleTray(cDL);
+ else
+ return S_OK;
+}
+
+// safe removal of USB drives:
+// http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
+// http://www.techtalkz.com/microsoft-device-drivers/250734-remove-usb-device-c-3.html
+
+DEVINST CWIN32Util::GetDrivesDevInstByDiskNumber(long DiskNumber)
+{
+
+ GUID* guid = (GUID*)(void*)&GUID_DEVINTERFACE_DISK;
+
+ // Get device interface info set handle for all devices attached to system
+ HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ if (hDevInfo == INVALID_HANDLE_VALUE)
+ return 0;
+
+ // Retrieve a context structure for a device interface of a device
+ // information set.
+ DWORD dwIndex = 0;
+ SP_DEVICE_INTERFACE_DATA devInterfaceData = {0};
+ devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ BOOL bRet = FALSE;
+
+ PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
+ SP_DEVICE_INTERFACE_DATA spdid;
+ SP_DEVINFO_DATA spdd;
+ DWORD dwSize;
+
+ spdid.cbSize = sizeof(spdid);
+
+ while ( true )
+ {
+ bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &devInterfaceData);
+ if (!bRet)
+ break;
+
+ SetupDiEnumInterfaceDevice(hDevInfo, NULL, guid, dwIndex, &spdid);
+
+ dwSize = 0;
+ SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);
+
+ if ( dwSize )
+ {
+ pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
+ if ( pspdidd == NULL )
+ continue;
+
+ pspdidd->cbSize = sizeof(*pspdidd);
+ ZeroMemory((PVOID)&spdd, sizeof(spdd));
+ spdd.cbSize = sizeof(spdd);
+
+ long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid,
+ pspdidd, dwSize, &dwSize, &spdd);
+ if ( res )
+ {
+ HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
+ if ( hDrive != INVALID_HANDLE_VALUE )
+ {
+ STORAGE_DEVICE_NUMBER sdn;
+ DWORD dwBytesReturned = 0;
+ res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
+ if ( res )
+ {
+ if ( DiskNumber == (long)sdn.DeviceNumber )
+ {
+ CloseHandle(hDrive);
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return spdd.DevInst;
+ }
+ }
+ CloseHandle(hDrive);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, pspdidd);
+ }
+ dwIndex++;
+ }
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return 0;
+}
+
+bool CWIN32Util::EjectDrive(const char cDriveLetter)
+{
+ if( !cDriveLetter )
+ return false;
+
+ std::string strVolFormat = StringUtils::Format("\\\\.\\%c:", cDriveLetter);
+
+ long DiskNumber = -1;
+
+ HANDLE hVolume = CreateFile(strVolFormat.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
+ if (hVolume == INVALID_HANDLE_VALUE)
+ return false;
+
+ STORAGE_DEVICE_NUMBER sdn;
+ DWORD dwBytesReturned = 0;
+ long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER,NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
+ CloseHandle(hVolume);
+ if ( res )
+ DiskNumber = sdn.DeviceNumber;
+ else
+ return false;
+
+ DEVINST DevInst = GetDrivesDevInstByDiskNumber(DiskNumber);
+
+ if ( DevInst == 0 )
+ return false;
+
+ ULONG Status = 0;
+ ULONG ProblemNumber = 0;
+ PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
+ char VetoName[MAX_PATH];
+ bool bSuccess = false;
+
+ res = CM_Get_Parent(&DevInst, DevInst, 0); // disk's parent, e.g. the USB bridge, the SATA controller....
+ res = CM_Get_DevNode_Status(&Status, &ProblemNumber, DevInst, 0);
+
+ for(int i=0;i<3;i++)
+ {
+ res = CM_Request_Device_Eject(DevInst, &VetoType, VetoName, MAX_PATH, 0);
+ bSuccess = (res==CR_SUCCESS && VetoType==PNP_VetoTypeUnknown);
+ if ( bSuccess )
+ break;
+ }
+
+ return bSuccess;
+}
+
+#ifdef HAS_GL
+void CWIN32Util::CheckGLVersion()
+{
+ if(CWIN32Util::HasGLDefaultDrivers())
+ {
+ MessageBox(NULL, "MS default OpenGL drivers detected. Please get OpenGL drivers from your video card vendor", "XBMC: Fatal Error", MB_OK|MB_ICONERROR);
+ exit(1);
+ }
+
+ if(!CWIN32Util::HasReqGLVersion())
+ {
+ if(MessageBox(NULL, "Your OpenGL version doesn't meet the XBMC requirements", "XBMC: Warning", MB_OKCANCEL|MB_ICONWARNING) == IDCANCEL)
+ {
+ exit(1);
+ }
+ }
+}
+
+bool CWIN32Util::HasGLDefaultDrivers()
+{
+ unsigned int a=0,b=0;
+
+ CStdString strVendor = g_Windowing.GetRenderVendor();
+ g_Windowing.GetRenderVersion(a, b);
+
+ if(strVendor.find("Microsoft")!=strVendor.npos && a==1 && b==1)
+ return true;
+ else
+ return false;
+}
+
+bool CWIN32Util::HasReqGLVersion()
+{
+ unsigned int a=0,b=0;
+
+ g_Windowing.GetRenderVersion(a, b);
+ if((a>=2) || (a == 1 && b >= 3))
+ return true;
+ else
+ return false;
+}
+#endif
+
+BOOL CWIN32Util::IsCurrentUserLocalAdministrator()
+{
+ BOOL b;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ PSID AdministratorsGroup;
+ b = AllocateAndInitializeSid(
+ &NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdministratorsGroup);
+ if(b)
+ {
+ if (!CheckTokenMembership( NULL, AdministratorsGroup, &b))
+ {
+ b = FALSE;
+ }
+ FreeSid(AdministratorsGroup);
+ }
+
+ return(b);
+}
+
+void CWIN32Util::GetDrivesByType(VECSOURCES &localDrives, Drive_Types eDriveType, bool bonlywithmedia)
+{
+ WCHAR* pcBuffer= NULL;
+ DWORD dwStrLength= GetLogicalDriveStringsW( 0, pcBuffer );
+ if( dwStrLength != 0 )
+ {
+ CMediaSource share;
+
+ dwStrLength+= 1;
+ pcBuffer= new WCHAR [dwStrLength];
+ GetLogicalDriveStringsW( dwStrLength, pcBuffer );
+
+ int iPos= 0;
+ WCHAR cVolumeName[100];
+ do{
+ int nResult = 0;
+ cVolumeName[0]= L'\0';
+
+ std::wstring strWdrive = pcBuffer + iPos;
+
+ UINT uDriveType= GetDriveTypeW( strWdrive.c_str() );
+ // don't use GetVolumeInformation on fdd's as the floppy controller may be enabled in Bios but
+ // no floppy HW is attached which causes huge delays.
+ if(strWdrive.size() >= 2 && strWdrive.substr(0,2) != L"A:" && strWdrive.substr(0,2) != L"B:")
+ nResult= GetVolumeInformationW( strWdrive.c_str() , cVolumeName, 100, 0, 0, 0, NULL, 25);
+ if(nResult == 0 && bonlywithmedia)
+ {
+ iPos += (wcslen( pcBuffer + iPos) + 1 );
+ continue;
+ }
+
+ // usb hard drives are reported as DRIVE_FIXED and won't be returned by queries with REMOVABLE_DRIVES set
+ // so test for usb hard drives
+ /*if(uDriveType == DRIVE_FIXED)
+ {
+ if(IsUsbDevice(strWdrive))
+ uDriveType = DRIVE_REMOVABLE;
+ }*/
+
+ share.strPath= share.strName= "";
+
+ bool bUseDCD= false;
+ if( uDriveType > DRIVE_UNKNOWN &&
+ (( eDriveType == ALL_DRIVES && (uDriveType == DRIVE_FIXED || uDriveType == DRIVE_REMOTE || uDriveType == DRIVE_CDROM || uDriveType == DRIVE_REMOVABLE )) ||
+ ( eDriveType == LOCAL_DRIVES && (uDriveType == DRIVE_FIXED || uDriveType == DRIVE_REMOTE)) ||
+ ( eDriveType == REMOVABLE_DRIVES && ( uDriveType == DRIVE_REMOVABLE )) ||
+ ( eDriveType == DVD_DRIVES && ( uDriveType == DRIVE_CDROM ))))
+ {
+ //share.strPath = strWdrive;
+ g_charsetConverter.wToUTF8(strWdrive, share.strPath);
+ if( cVolumeName[0] != L'\0' )
+ g_charsetConverter.wToUTF8(cVolumeName, share.strName);
+ if( uDriveType == DRIVE_CDROM && nResult)
+ {
+ // Has to be the same as auto mounted devices
+ share.strStatus = share.strName;
+ share.strName = share.strPath;
+ share.m_iDriveType= CMediaSource::SOURCE_TYPE_LOCAL;
+ bUseDCD= true;
+ }
+ else
+ {
+ // Lets show it, like Windows explorer do... TODO: sorting should depend on driver letter
+ switch(uDriveType)
+ {
+ case DRIVE_CDROM:
+ share.strName = StringUtils::Format( "%s (%s)", share.strPath.c_str(), g_localizeStrings.Get(218).c_str());
+ break;
+ case DRIVE_REMOVABLE:
+ if(share.strName.empty())
+ share.strName = StringUtils::Format( "%s (%s)", g_localizeStrings.Get(437).c_str(), share.strPath.c_str());
+ break;
+ case DRIVE_UNKNOWN:
+ share.strName = StringUtils::Format( "%s (%s)", share.strPath.c_str(), g_localizeStrings.Get(13205).c_str());
+ break;
+ default:
+ if(share.strName.empty())
+ share.strName = share.strPath;
+ else
+ share.strName = StringUtils::Format( "%s (%s)", share.strPath.c_str(), share.strName.c_str());
+ break;
+ }
+ }
+ StringUtils::Replace(share.strName, ":\\", ":");
+ StringUtils::Replace(share.strPath, ":\\", ":");
+ share.m_ignore= true;
+ if( !bUseDCD )
+ {
+ share.m_iDriveType= (
+ ( uDriveType == DRIVE_FIXED ) ? CMediaSource::SOURCE_TYPE_LOCAL :
+ ( uDriveType == DRIVE_REMOTE ) ? CMediaSource::SOURCE_TYPE_REMOTE :
+ ( uDriveType == DRIVE_CDROM ) ? CMediaSource::SOURCE_TYPE_DVD :
+ ( uDriveType == DRIVE_REMOVABLE ) ? CMediaSource::SOURCE_TYPE_REMOVABLE :
+ CMediaSource::SOURCE_TYPE_UNKNOWN );
+ }
+
+ AddOrReplace(localDrives, share);
+ }
+ iPos += (wcslen( pcBuffer + iPos) + 1 );
+ } while( wcslen( pcBuffer + iPos ) > 0 );
+ delete[] pcBuffer;
+ }
+}
+
+std::string CWIN32Util::GetFirstOpticalDrive()
+{
+ VECSOURCES vShare;
+ std::string strdevice = "\\\\.\\";
+ CWIN32Util::GetDrivesByType(vShare, DVD_DRIVES);
+ if(!vShare.empty())
+ return strdevice.append(vShare.front().strPath);
+ else
+ return "";
+}
+
+extern "C"
+{
+ FILE *fopen_utf8(const char *_Filename, const char *_Mode)
+ {
+ CStdStringW wfilename, wmode;
+ g_charsetConverter.utf8ToW(_Filename, wfilename, false);
+ wmode = _Mode;
+ return _wfopen(wfilename.c_str(), wmode.c_str());
+ }
+}
+
+extern "C" {
+ /*
+ * Ported from NetBSD to Windows by Ron Koenderink, 2007
+ */
+
+ /* $NetBSD: strptime.c,v 1.25 2005/11/29 03:12:00 christos Exp $ */
+
+ /*-
+ * Copyright (c) 1997, 1998, 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Klaus Klein.
+ * Heavily optimised by David Laight
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ #if !defined(TARGET_WINDOWS)
+ #include <sys/cdefs.h>
+ #endif
+
+ #if defined(LIBC_SCCS) && !defined(lint)
+ __RCSID("$NetBSD: strptime.c,v 1.25 2005/11/29 03:12:00 christos Exp $");
+ #endif
+
+ #if !defined(TARGET_WINDOWS)
+ #include "namespace.h"
+ #include <sys/localedef.h>
+ #else
+ typedef unsigned char u_char;
+ typedef unsigned int uint;
+ #endif
+ #include <ctype.h>
+ #include <locale.h>
+ #include <string.h>
+ #include <time.h>
+ #if !defined(TARGET_WINDOWS)
+ #include <tzfile.h>
+ #endif
+
+ #ifdef __weak_alias
+ __weak_alias(strptime,_strptime)
+ #endif
+
+ #if !defined(TARGET_WINDOWS)
+ #define _ctloc(x) (_CurrentTimeLocale->x)
+ #else
+ #define _ctloc(x) (x)
+ const char *abday[] = {
+ "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat"
+ };
+ const char *day[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+ };
+ const char *abmon[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ const char *mon[] = {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ };
+ const char *am_pm[] = {
+ "AM", "PM"
+ };
+ char *d_t_fmt = "%a %Ef %T %Y";
+ char *t_fmt_ampm = "%I:%M:%S %p";
+ char *t_fmt = "%H:%M:%S";
+ char *d_fmt = "%m/%d/%y";
+ #define TM_YEAR_BASE 1900
+ #define __UNCONST(x) ((char *)(((const char *)(x) - (const char *)0) + (char *)0))
+
+ #endif
+ /*
+ * We do not implement alternate representations. However, we always
+ * check whether a given modifier is allowed for a certain conversion.
+ */
+ #define ALT_E 0x01
+ #define ALT_O 0x02
+ #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; }
+
+
+ static const u_char *conv_num(const unsigned char *, int *, uint, uint);
+ static const u_char *find_string(const u_char *, int *, const char * const *,
+ const char * const *, int);
+
+
+ char *
+ strptime(const char *buf, const char *fmt, struct tm *tm)
+ {
+ unsigned char c;
+ const unsigned char *bp;
+ int alt_format, i, split_year = 0;
+ const char *new_fmt;
+
+ bp = (const u_char *)buf;
+
+ while (bp != NULL && (c = *fmt++) != '\0') {
+ /* Clear `alternate' modifier prior to new conversion. */
+ alt_format = 0;
+ i = 0;
+
+ /* Eat up white-space. */
+ if (isspace(c)) {
+ while (isspace(*bp))
+ bp++;
+ continue;
+ }
+
+ if (c != '%')
+ goto literal;
+
+
+ again: switch (c = *fmt++) {
+ case '%': /* "%%" is converted to "%". */
+ literal:
+ if (c != *bp++)
+ return NULL;
+ LEGAL_ALT(0);
+ continue;
+
+ /*
+ * "Alternative" modifiers. Just set the appropriate flag
+ * and start over again.
+ */
+ case 'E': /* "%E?" alternative conversion modifier. */
+ LEGAL_ALT(0);
+ alt_format |= ALT_E;
+ goto again;
+
+ case 'O': /* "%O?" alternative conversion modifier. */
+ LEGAL_ALT(0);
+ alt_format |= ALT_O;
+ goto again;
+
+ /*
+ * "Complex" conversion rules, implemented through recursion.
+ */
+ case 'c': /* Date and time, using the locale's format. */
+ new_fmt = _ctloc(d_t_fmt);
+ goto recurse;
+
+ case 'D': /* The date as "%m/%d/%y". */
+ new_fmt = "%m/%d/%y";
+ LEGAL_ALT(0);
+ goto recurse;
+
+ case 'R': /* The time as "%H:%M". */
+ new_fmt = "%H:%M";
+ LEGAL_ALT(0);
+ goto recurse;
+
+ case 'r': /* The time in 12-hour clock representation. */
+ new_fmt =_ctloc(t_fmt_ampm);
+ LEGAL_ALT(0);
+ goto recurse;
+
+ case 'T': /* The time as "%H:%M:%S". */
+ new_fmt = "%H:%M:%S";
+ LEGAL_ALT(0);
+ goto recurse;
+
+ case 'X': /* The time, using the locale's format. */
+ new_fmt =_ctloc(t_fmt);
+ goto recurse;
+
+ case 'x': /* The date, using the locale's format. */
+ new_fmt =_ctloc(d_fmt);
+ recurse:
+ bp = (const u_char *)strptime((const char *)bp,
+ new_fmt, tm);
+ LEGAL_ALT(ALT_E);
+ continue;
+
+ /*
+ * "Elementary" conversion rules.
+ */
+ case 'A': /* The day of week, using the locale's form. */
+ case 'a':
+ bp = find_string(bp, &tm->tm_wday, _ctloc(day),
+ _ctloc(abday), 7);
+ LEGAL_ALT(0);
+ continue;
+
+ case 'B': /* The month, using the locale's form. */
+ case 'b':
+ case 'h':
+ bp = find_string(bp, &tm->tm_mon, _ctloc(mon),
+ _ctloc(abmon), 12);
+ LEGAL_ALT(0);
+ continue;
+
+ case 'C': /* The century number. */
+ i = 20;
+ bp = conv_num(bp, &i, 0, 99);
+
+ i = i * 100 - TM_YEAR_BASE;
+ if (split_year)
+ i += tm->tm_year % 100;
+ split_year = 1;
+ tm->tm_year = i;
+ LEGAL_ALT(ALT_E);
+ continue;
+
+ case 'd': /* The day of month. */
+ case 'e':
+ bp = conv_num(bp, &tm->tm_mday, 1, 31);
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'k': /* The hour (24-hour clock representation). */
+ LEGAL_ALT(0);
+ /* FALLTHROUGH */
+ case 'H':
+ bp = conv_num(bp, &tm->tm_hour, 0, 23);
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'l': /* The hour (12-hour clock representation). */
+ LEGAL_ALT(0);
+ /* FALLTHROUGH */
+ case 'I':
+ bp = conv_num(bp, &tm->tm_hour, 1, 12);
+ if (tm->tm_hour == 12)
+ tm->tm_hour = 0;
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'j': /* The day of year. */
+ i = 1;
+ bp = conv_num(bp, &i, 1, 366);
+ tm->tm_yday = i - 1;
+ LEGAL_ALT(0);
+ continue;
+
+ case 'M': /* The minute. */
+ bp = conv_num(bp, &tm->tm_min, 0, 59);
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'm': /* The month. */
+ i = 1;
+ bp = conv_num(bp, &i, 1, 12);
+ tm->tm_mon = i - 1;
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'p': /* The locale's equivalent of AM/PM. */
+ bp = find_string(bp, &i, _ctloc(am_pm), NULL, 2);
+ if (tm->tm_hour > 11)
+ return NULL;
+ tm->tm_hour += i * 12;
+ LEGAL_ALT(0);
+ continue;
+
+ case 'S': /* The seconds. */
+ bp = conv_num(bp, &tm->tm_sec, 0, 61);
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'U': /* The week of year, beginning on sunday. */
+ case 'W': /* The week of year, beginning on monday. */
+ /*
+ * XXX This is bogus, as we can not assume any valid
+ * information present in the tm structure at this
+ * point to calculate a real value, so just check the
+ * range for now.
+ */
+ bp = conv_num(bp, &i, 0, 53);
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'w': /* The day of week, beginning on sunday. */
+ bp = conv_num(bp, &tm->tm_wday, 0, 6);
+ LEGAL_ALT(ALT_O);
+ continue;
+
+ case 'Y': /* The year. */
+ i = TM_YEAR_BASE; /* just for data sanity... */
+ bp = conv_num(bp, &i, 0, 9999);
+ tm->tm_year = i - TM_YEAR_BASE;
+ LEGAL_ALT(ALT_E);
+ continue;
+
+ case 'y': /* The year within 100 years of the epoch. */
+ /* LEGAL_ALT(ALT_E | ALT_O); */
+ bp = conv_num(bp, &i, 0, 99);
+
+ if (split_year)
+ /* preserve century */
+ i += (tm->tm_year / 100) * 100;
+ else {
+ split_year = 1;
+ if (i <= 68)
+ i = i + 2000 - TM_YEAR_BASE;
+ else
+ i = i + 1900 - TM_YEAR_BASE;
+ }
+ tm->tm_year = i;
+ continue;
+
+ /*
+ * Miscellaneous conversions.
+ */
+ case 'n': /* Any kind of white-space. */
+ case 't':
+ while (isspace(*bp))
+ bp++;
+ LEGAL_ALT(0);
+ continue;
+
+
+ default: /* Unknown/unsupported conversion. */
+ return NULL;
+ }
+ }
+
+ return __UNCONST(bp);
+ }
+
+
+ static const u_char *
+ conv_num(const unsigned char *buf, int *dest, uint llim, uint ulim)
+ {
+ uint result = 0;
+ unsigned char ch;
+
+ /* The limit also determines the number of valid digits. */
+ uint rulim = ulim;
+
+ ch = *buf;
+ if (ch < '0' || ch > '9')
+ return NULL;
+
+ do {
+ result *= 10;
+ result += ch - '0';
+ rulim /= 10;
+ ch = *++buf;
+ } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9');
+
+ if (result < llim || result > ulim)
+ return NULL;
+
+ *dest = result;
+ return buf;
+ }
+
+ static const u_char *
+ find_string(const u_char *bp, int *tgt, const char * const *n1,
+ const char * const *n2, int c)
+ {
+ int i;
+ unsigned int len;
+
+ /* check full name - then abbreviated ones */
+ for (; n1 != NULL; n1 = n2, n2 = NULL) {
+ for (i = 0; i < c; i++, n1++) {
+ len = strlen(*n1);
+ if (strnicmp(*n1, (const char *)bp, len) == 0) {
+ *tgt = i;
+ return bp + len;
+ }
+ }
+ }
+
+ /* Nothing matched */
+ return NULL;
+ }
+}
+
+
+LONG CWIN32Util::UtilRegGetValue( const HKEY hKey, const char *const pcKey, DWORD *const pdwType, char **const ppcBuffer, DWORD *const pdwSizeBuff, const DWORD dwSizeAdd )
+{
+ DWORD dwSize;
+ LONG lRet= RegQueryValueEx(hKey, pcKey, NULL, pdwType, NULL, &dwSize );
+ if (lRet == ERROR_SUCCESS)
+ {
+ if (ppcBuffer)
+ {
+ char *pcValue=*ppcBuffer;
+ if (!pcValue || !pdwSizeBuff || dwSize +dwSizeAdd > *pdwSizeBuff) pcValue= (char*)realloc(pcValue, dwSize +dwSizeAdd);
+ lRet= RegQueryValueEx(hKey,pcKey,NULL,NULL,(LPBYTE)pcValue,&dwSize);
+
+ if ( lRet == ERROR_SUCCESS || *ppcBuffer ) *ppcBuffer= pcValue;
+ else free( pcValue );
+ }
+ if (pdwSizeBuff) *pdwSizeBuff= dwSize +dwSizeAdd;
+ }
+ return lRet;
+}
+
+bool CWIN32Util::UtilRegOpenKeyEx( const HKEY hKeyParent, const char *const pcKey, const REGSAM rsAccessRights, HKEY *hKey, const bool bReadX64 )
+{
+ const REGSAM rsAccessRightsTmp= ( CSysInfo::GetKernelBitness() == 64 ? rsAccessRights | ( bReadX64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY ) : rsAccessRights );
+ bool bRet= ( ERROR_SUCCESS == RegOpenKeyEx(hKeyParent, pcKey, 0, rsAccessRightsTmp, hKey));
+ return bRet;
+}
+
+// Retrieve the filename of the process that currently has the focus.
+// Typically this will be some process using the system tray grabbing
+// the focus and causing XBMC to minimise. Logging the offending
+// process name can help the user fix the problem.
+bool CWIN32Util::GetFocussedProcess(std::string &strProcessFile)
+{
+ strProcessFile = "";
+
+ // Get the window that has the focus
+ HWND hfocus = GetForegroundWindow();
+ if (!hfocus)
+ return false;
+
+ // Get the process ID from the window handle
+ DWORD pid = 0;
+ GetWindowThreadProcessId(hfocus, &pid);
+
+ // Use OpenProcess to get the process handle from the process ID
+ HANDLE hproc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid);
+ if (!hproc)
+ return false;
+
+ // Load QueryFullProcessImageName dynamically because it isn't available
+ // in all versions of Windows.
+ char procfile[MAX_PATH+1];
+ DWORD procfilelen = MAX_PATH;
+
+ HINSTANCE hkernel32 = LoadLibrary("kernel32.dll");
+ if (hkernel32)
+ {
+ DWORD (WINAPI *pQueryFullProcessImageNameA)(HANDLE,DWORD,LPTSTR,PDWORD);
+ pQueryFullProcessImageNameA = (DWORD (WINAPI *)(HANDLE,DWORD,LPTSTR,PDWORD)) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
+ if (pQueryFullProcessImageNameA)
+ if (pQueryFullProcessImageNameA(hproc, 0, procfile, &procfilelen))
+ strProcessFile = procfile;
+ FreeLibrary(hkernel32);
+ }
+
+ // If QueryFullProcessImageName failed fall back to GetModuleFileNameEx.
+ // Note this does not work across x86-x64 boundaries.
+ if (strProcessFile == "")
+ {
+ HINSTANCE hpsapi = LoadLibrary("psapi.dll");
+ if (hpsapi)
+ {
+ DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE,HMODULE,LPTSTR,DWORD);
+ pGetModuleFileNameExA = (DWORD (WINAPI*)(HANDLE,HMODULE,LPTSTR,DWORD)) GetProcAddress(hpsapi, "GetModuleFileNameExA");
+ if (pGetModuleFileNameExA)
+ if (pGetModuleFileNameExA(hproc, NULL, procfile, MAX_PATH))
+ strProcessFile = procfile;
+ FreeLibrary(hpsapi);
+ }
+ }
+
+ CloseHandle(hproc);
+
+ return true;
+}
+
+// Adjust the src rectangle so that the dst is always contained in the target rectangle.
+void CWIN32Util::CropSource(CRect& src, CRect& dst, CRect target)
+{
+ if(dst.x1 < target.x1)
+ {
+ src.x1 -= (dst.x1 - target.x1)
+ * (src.x2 - src.x1)
+ / (dst.x2 - dst.x1);
+ dst.x1 = target.x1;
+ }
+ if(dst.y1 < target.y1)
+ {
+ src.y1 -= (dst.y1 - target.y1)
+ * (src.y2 - src.y1)
+ / (dst.y2 - dst.y1);
+ dst.y1 = target.y1;
+ }
+ if(dst.x2 > target.x2)
+ {
+ src.x2 -= (dst.x2 - target.x2)
+ * (src.x2 - src.x1)
+ / (dst.x2 - dst.x1);
+ dst.x2 = target.x2;
+ }
+ if(dst.y2 > target.y2)
+ {
+ src.y2 -= (dst.y2 - target.y2)
+ * (src.y2 - src.y1)
+ / (dst.y2 - dst.y1);
+ dst.y2 = target.y2;
+ }
+ // Callers expect integer coordinates.
+ src.x1 = floor(src.x1);
+ src.y1 = floor(src.y1);
+ src.x2 = ceil(src.x2);
+ src.y2 = ceil(src.y2);
+ dst.x1 = floor(dst.x1);
+ dst.y1 = floor(dst.y1);
+ dst.x2 = ceil(dst.x2);
+ dst.y2 = ceil(dst.y2);
+}
+
+void CWinIdleTimer::StartZero()
+{
+ SetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED);
+ CStopWatch::StartZero();
+}
+
+extern "C"
+{
+ /* case-independent string matching, similar to strstr but
+ * matching */
+ char * strcasestr(const char* haystack, const char* needle)
+ {
+ int i;
+ int nlength = (int) strlen (needle);
+ int hlength = (int) strlen (haystack);
+
+ if (nlength > hlength) return NULL;
+ if (hlength <= 0) return NULL;
+ if (nlength <= 0) return (char *)haystack;
+ /* hlength and nlength > 0, nlength <= hlength */
+ for (i = 0; i <= (hlength - nlength); i++)
+ {
+ if (strncasecmp (haystack + i, needle, nlength) == 0)
+ {
+ return (char *)haystack + i;
+ }
+ }
+ /* substring not found */
+ return NULL;
+ }
+}
+
+// detect if a drive is a usb device
+// code taken from http://banderlogi.blogspot.com/2011/06/enum-drive-letters-attached-for-usb.html
+
+bool CWIN32Util::IsUsbDevice(const std::wstring &strWdrive)
+{
+ if (strWdrive.size() < 2)
+ return false;
+
+ std::wstring strWDevicePath = StringUtils::Format(L"\\\\.\\%s",strWdrive.substr(0, 2).c_str());
+
+ HANDLE deviceHandle = CreateFileW(
+ strWDevicePath.c_str(),
+ 0, // no access to the drive
+ FILE_SHARE_READ | // share mode
+ FILE_SHARE_WRITE,
+ NULL, // default security attributes
+ OPEN_EXISTING, // disposition
+ 0, // file attributes
+ NULL); // do not copy file attributes
+
+ if(deviceHandle == INVALID_HANDLE_VALUE)
+ return false;
+
+ // setup query
+ STORAGE_PROPERTY_QUERY query;
+ memset(&query, 0, sizeof(query));
+ query.PropertyId = StorageDeviceProperty;
+ query.QueryType = PropertyStandardQuery;
+
+ // issue query
+ DWORD bytes;
+ STORAGE_DEVICE_DESCRIPTOR devd;
+ STORAGE_BUS_TYPE busType = BusTypeUnknown;
+
+ if (DeviceIoControl(deviceHandle,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &query, sizeof(query),
+ &devd, sizeof(devd),
+ &bytes, NULL))
+ {
+ busType = devd.BusType;
+ }
+
+ CloseHandle(deviceHandle);
+
+ return BusTypeUsb == busType;
+ }
+
+std::string CWIN32Util::WUSysMsg(DWORD dwError)
+{
+ #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
+ CHAR szBuf[512];
+
+ if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
+ SS_DEFLANGID, szBuf, 511, NULL) )
+ return StringUtils::Format("%s (0x%X)", szBuf, dwError);
+ else
+ return StringUtils::Format("Unknown error (0x%X)", dwError);
+}