/*
* (C) 2011-2015 see Authors.txt
*
* This file is part of MPC-HC.
*
* MPC-HC 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 3 of the License, or
* (at your option) any later version.
*
* MPC-HC 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 this program. If not, see .
*
*/
#include "stdafx.h"
#include
#include
#include "WinAPIUtils.h"
#include "SysVersion.h"
#include "PathUtils.h"
bool SetPrivilege(LPCTSTR privilege, bool bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
SetThreadExecutionState(ES_CONTINUOUS);
// Get a token for this process.
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
return false;
}
// Get the LUID for the privilege.
LookupPrivilegeValue(nullptr, privilege, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
// Set the privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)nullptr, 0);
return (GetLastError() == ERROR_SUCCESS);
}
CString GetHiveName(const HKEY hive)
{
switch ((ULONG_PTR)hive) {
case (ULONG_PTR)HKEY_CLASSES_ROOT:
return _T("HKEY_CLASSES_ROOT");
case (ULONG_PTR)HKEY_CURRENT_USER:
return _T("HKEY_CURRENT_USER");
case (ULONG_PTR)HKEY_LOCAL_MACHINE:
return _T("HKEY_LOCAL_MACHINE");
case (ULONG_PTR)HKEY_USERS:
return _T("HKEY_USERS");
case (ULONG_PTR)HKEY_PERFORMANCE_DATA:
return _T("HKEY_PERFORMANCE_DATA");
case (ULONG_PTR)HKEY_CURRENT_CONFIG:
return _T("HKEY_CURRENT_CONFIG");
case (ULONG_PTR)HKEY_DYN_DATA:
return _T("HKEY_DYN_DATA");
case (ULONG_PTR)HKEY_PERFORMANCE_TEXT:
return _T("HKEY_PERFORMANCE_TEXT");
case (ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT:
return _T("HKEY_PERFORMANCE_NLSTEXT");
default:
return _T("");
}
}
bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName)
{
// Registry functions don't set GetLastError(), so it needs to be set explicitly
LSTATUS errorCode = ERROR_SUCCESS;
HKEY hKey = nullptr;
errorCode = RegOpenKeyEx(hKeyRoot, keyName, 0, KEY_READ, &hKey);
if (errorCode != ERROR_SUCCESS) {
SetLastError(errorCode);
return false;
}
DWORD subKeysCount = 0, maxSubKeyLen = 0;
DWORD valuesCount = 0, maxValueNameLen = 0, maxValueDataLen = 0;
errorCode = RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, &subKeysCount, &maxSubKeyLen, nullptr, &valuesCount, &maxValueNameLen, &maxValueDataLen, nullptr, nullptr);
if (errorCode != ERROR_SUCCESS) {
SetLastError(errorCode);
return false;
}
maxSubKeyLen += 1;
maxValueNameLen += 1;
CString buffer;
buffer.Format(_T("[%s\\%s]\n"), GetHiveName(hKeyRoot), keyName);
file.WriteString(buffer);
CString valueName;
DWORD valueNameLen, valueDataLen, type;
BYTE* data = DEBUG_NEW BYTE[maxValueDataLen];
for (DWORD indexValue = 0; indexValue < valuesCount; indexValue++) {
valueNameLen = maxValueNameLen;
valueDataLen = maxValueDataLen;
errorCode = RegEnumValue(hKey, indexValue, valueName.GetBuffer(maxValueNameLen), &valueNameLen, nullptr, &type, data, &valueDataLen);
if (errorCode != ERROR_SUCCESS) {
SetLastError(errorCode);
return false;
}
switch (type) {
case REG_SZ: {
CString str((TCHAR*)data);
str.Replace(_T("\\"), _T("\\\\"));
str.Replace(_T("\""), _T("\\\""));
buffer.Format(_T("\"%s\"=\"%s\"\n"), valueName, str);
file.WriteString(buffer);
}
break;
case REG_BINARY:
buffer.Format(_T("\"%s\"=hex:%02x"), valueName, data[0]);
file.WriteString(buffer);
for (DWORD i = 1; i < valueDataLen; i++) {
buffer.Format(_T(",%02x"), data[i]);
file.WriteString(buffer);
}
file.WriteString(_T("\n"));
break;
case REG_DWORD:
buffer.Format(_T("\"%s\"=dword:%08lx\n"), valueName, *((DWORD*)data));
file.WriteString(buffer);
break;
default: {
CString msg;
msg.Format(_T("The value \"%s\\%s\\%s\" has an unsupported type and has been ignored.\nPlease report this error to the developers."),
GetHiveName(hKeyRoot), keyName, valueName);
AfxMessageBox(msg, MB_ICONERROR | MB_OK);
}
delete [] data;
return false;
}
}
delete [] data;
file.WriteString(_T("\n"));
CString subKeyName;
DWORD subKeyLen;
for (DWORD indexSubKey = 0; indexSubKey < subKeysCount; indexSubKey++) {
subKeyLen = maxSubKeyLen;
errorCode = RegEnumKeyEx(hKey, indexSubKey, subKeyName.GetBuffer(maxSubKeyLen), &subKeyLen, nullptr, nullptr, nullptr, nullptr);
if (errorCode != ERROR_SUCCESS) {
SetLastError(errorCode);
return false;
}
buffer.Format(_T("%s\\%s"), keyName, subKeyName);
if (!ExportRegistryKey(file, hKeyRoot, buffer)) {
return false;
}
}
errorCode = RegCloseKey(hKey);
SetLastError(errorCode);
return true;
}
UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd)
{
if (hWnd == nullptr || pD3D == nullptr) {
return D3DADAPTER_DEFAULT;
}
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
if (hMonitor == nullptr) {
return D3DADAPTER_DEFAULT;
}
for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) {
HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp);
if (hAdpMon == hMonitor) {
return adp;
}
}
return D3DADAPTER_DEFAULT;
}
int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX* /*lpelfe*/, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam)
{
LPARAM* l = (LPARAM*)lParam;
*l = TRUE;
return TRUE;
}
namespace
{
void GetNonClientMetrics(NONCLIENTMETRICS* ncm)
{
ZeroMemory(ncm, sizeof(NONCLIENTMETRICS));
ncm->cbSize = sizeof(NONCLIENTMETRICS);
if (!SysVersion::IsVistaOrLater()) {
ncm->cbSize -= sizeof(ncm->iPaddedBorderWidth);
}
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, 0));
}
}
void GetMessageFont(LOGFONT* lf)
{
NONCLIENTMETRICS ncm;
GetNonClientMetrics(&ncm);
*lf = ncm.lfMessageFont;
ASSERT(lf->lfHeight);
}
void GetStatusFont(LOGFONT* lf)
{
NONCLIENTMETRICS ncm;
GetNonClientMetrics(&ncm);
*lf = ncm.lfStatusFont;
ASSERT(lf->lfHeight);
}
bool IsFontInstalled(LPCTSTR lpszFont)
{
// Get the screen DC
CDC dc;
if (!dc.CreateCompatibleDC(nullptr)) {
return false;
}
LOGFONT lf;
ZeroMemory(&lf, sizeof(LOGFONT));
// Any character set will do
lf.lfCharSet = DEFAULT_CHARSET;
// Set the facename to check for
_tcscpy_s(lf.lfFaceName, lpszFont);
LPARAM lParam = 0;
// Enumerate fonts
EnumFontFamiliesEx(dc.GetSafeHdc(), &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&lParam, 0);
return lParam ? true : false;
}
bool ExploreToFile(LPCTSTR path)
{
CoInitializeHelper co;
bool success = false;
PIDLIST_ABSOLUTE pidl;
if (PathUtils::Exists(path) && SHParseDisplayName(path, nullptr, &pidl, 0, nullptr) == S_OK) {
success = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0));
CoTaskMemFree(pidl);
}
return success;
}
CoInitializeHelper::CoInitializeHelper()
{
HRESULT res = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (res == RPC_E_CHANGED_MODE) { // Try another threading model
res = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
}
if (res != S_OK && res != S_FALSE) {
throw res;
}
}
CoInitializeHelper::~CoInitializeHelper()
{
CoUninitialize();
}
HRESULT FileDelete(CString file, HWND hWnd, bool recycle /*= true*/)
{
// Strings in SHFILEOPSTRUCT must be double-null terminated
file.AppendChar(_T('\0'));
SHFILEOPSTRUCT fileOpStruct;
ZeroMemory(&fileOpStruct, sizeof(SHFILEOPSTRUCT));
fileOpStruct.hwnd = hWnd;
fileOpStruct.wFunc = FO_DELETE;
fileOpStruct.pFrom = file;
if (recycle) {
fileOpStruct.fFlags = FOF_ALLOWUNDO | FOF_WANTNUKEWARNING;
}
int hRes = SHFileOperation(&fileOpStruct);
if (fileOpStruct.fAnyOperationsAborted) {
hRes = E_ABORT;
}
TRACE(_T("Delete recycle=%d hRes=0x%08x, file=%s\n"), recycle, hRes, file);
return hRes;
}