You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1343 lines
42 KiB
1343 lines
42 KiB
/*****************************************************************************\
|
|
FILE: util.cpp
|
|
|
|
DESCRIPTION:
|
|
Shared stuff that operates on all classes.
|
|
|
|
BryanSt 4/4/2000 (Bryan Starbuck)
|
|
Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "priv.h"
|
|
#include <atlbase.h> // USES_CONVERSION
|
|
#include <errors.h> // \\themes\\inc
|
|
#include <ctxdef.h> // hydra stuff
|
|
#include <regapi.h> // WINSTATION_REG_NAME
|
|
#include "WMPAPITemp.h"
|
|
|
|
#define SECURITY_WIN32
|
|
#include <sspi.h>
|
|
extern "C" {
|
|
#include <Secext.h> // for GetUserNameEx()
|
|
}
|
|
|
|
|
|
#define DECL_CRTFREE
|
|
#include <crtfree.h>
|
|
|
|
#include "util.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// String Helpers
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HINSTANCE g_hinst; // My instance handle
|
|
HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
#ifdef DEBUG
|
|
DWORD g_TLSliStopWatchStartHi = 0xFFFFFFFF;
|
|
DWORD g_TLSliStopWatchStartLo = 0xFFFFFFFF;
|
|
LARGE_INTEGER g_liStopWatchFreq = {0};
|
|
#endif // DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Debug Timing Helpers
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef DEBUG
|
|
void DebugStartWatch(void)
|
|
{
|
|
LARGE_INTEGER liStopWatchStart;
|
|
|
|
if (-1 == g_TLSliStopWatchStartHi)
|
|
{
|
|
g_TLSliStopWatchStartHi = TlsAlloc();
|
|
g_TLSliStopWatchStartLo = TlsAlloc();
|
|
liStopWatchStart.QuadPart = 0;
|
|
|
|
QueryPerformanceFrequency(&g_liStopWatchFreq); // Only a one time call since it's value can't change while the system is running.
|
|
}
|
|
else
|
|
{
|
|
liStopWatchStart.HighPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartHi));
|
|
liStopWatchStart.LowPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartLo));
|
|
}
|
|
|
|
AssertMsg((0 == liStopWatchStart.QuadPart), TEXT("Someone else is using our perf timer. Stop nesting.")); // If you hit this, then the stopwatch is nested.
|
|
QueryPerformanceCounter(&liStopWatchStart);
|
|
|
|
TlsSetValue(g_TLSliStopWatchStartHi, IntToPtr(liStopWatchStart.HighPart));
|
|
TlsSetValue(g_TLSliStopWatchStartLo, IntToPtr(liStopWatchStart.LowPart));
|
|
}
|
|
|
|
DWORD DebugStopWatch(void)
|
|
{
|
|
LARGE_INTEGER liDiff;
|
|
LARGE_INTEGER liStopWatchStart;
|
|
|
|
QueryPerformanceCounter(&liDiff);
|
|
liStopWatchStart.HighPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartHi));
|
|
liStopWatchStart.LowPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartLo));
|
|
liDiff.QuadPart -= liStopWatchStart.QuadPart;
|
|
|
|
ASSERT(0 != g_liStopWatchFreq.QuadPart); // I don't like to fault with div 0.
|
|
DWORD dwTime = (DWORD)((liDiff.QuadPart * 1000) / g_liStopWatchFreq.QuadPart);
|
|
|
|
TlsSetValue(g_TLSliStopWatchStartHi, (LPVOID) 0);
|
|
TlsSetValue(g_TLSliStopWatchStartLo, (LPVOID) 0);
|
|
|
|
return dwTime;
|
|
}
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// String Helpers
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT HrSysAllocStringW(IN const OLECHAR * pwzSource, OUT BSTR * pbstrDest)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pbstrDest)
|
|
{
|
|
*pbstrDest = SysAllocString(pwzSource);
|
|
if (pwzSource)
|
|
{
|
|
if (*pbstrDest)
|
|
hr = S_OK;
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT HrSysAllocString(IN const OLECHAR * pwzSource, OUT BSTR * pbstrDest)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pbstrDest)
|
|
{
|
|
*pbstrDest = SysAllocString(pwzSource);
|
|
if (pwzSource)
|
|
{
|
|
if (*pbstrDest)
|
|
hr = S_OK;
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// File System Wrapping Helpers
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT HrSHFileOpDeleteFile(HWND hwnd, FILEOP_FLAGS dwFlags, LPTSTR pszPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SHFILEOPSTRUCT FileOp = {0};
|
|
|
|
pszPath[lstrlen(pszPath)+1] = 0; // Ensure double terminated.
|
|
|
|
FileOp.wFunc = FO_DELETE;
|
|
FileOp.fAnyOperationsAborted = TRUE;
|
|
FileOp.hwnd = hwnd;
|
|
FileOp.pFrom = pszPath;
|
|
FileOp.fFlags = dwFlags;
|
|
|
|
if (SHFileOperation(&FileOp))
|
|
{
|
|
hr = ResultFromLastError();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Registry Helpers
|
|
/////////////////////////////////////////////////////////////////////
|
|
HRESULT HrRegOpenKeyEx(HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
|
|
{
|
|
DWORD dwError = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrRegCreateKeyEx(HKEY hKey, LPCTSTR lpSubKey, DWORD Reserved, LPTSTR lpClass, DWORD dwOptions,
|
|
REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition)
|
|
{
|
|
DWORD dwError = RegCreateKeyEx(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrRegQueryValueEx(IN HKEY hKey, IN LPCTSTR lpValueName, IN LPDWORD lpReserved, IN LPDWORD lpType, IN LPBYTE lpData, IN LPDWORD lpcbData)
|
|
{
|
|
DWORD dwError = RegQueryValueEx(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrRegSetValueEx(IN HKEY hKey, IN LPCTSTR lpValueName, IN DWORD dwReserved, IN DWORD dwType, IN CONST BYTE *lpData, IN DWORD cbData)
|
|
{
|
|
DWORD dwError = RegSetValueEx(hKey, lpValueName, dwReserved, dwType, lpData, cbData);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrRegEnumValue(HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcValueName, LPDWORD lpReserved,
|
|
LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
|
|
{
|
|
DWORD dwError = RegEnumValue(hKey, dwIndex, lpValueName, lpcValueName, lpReserved, lpType, lpData, lpcbData);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrRegQueryInfoKey(HKEY hKey, LPTSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen,
|
|
LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
|
|
{
|
|
DWORD dwError = RegQueryInfoKey(hKey, lpClass, lpcClass, lpReserved, lpcSubKeys, lpcMaxSubKeyLen,
|
|
lpcMaxClassLen, lpcValues, lpcMaxValueNameLen, lpcMaxValueLen, lpcbSecurityDescriptor, lpftLastWriteTime);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrBStrRegQueryValue(IN HKEY hKey, IN LPCTSTR lpValueName, OUT BSTR * pbstr)
|
|
{
|
|
TCHAR szValue[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD cbSize = sizeof(szValue);
|
|
HRESULT hr = HrRegQueryValueEx(hKey, lpValueName, 0, &dwType, (BYTE *)szValue, &cbSize);
|
|
|
|
*pbstr = NULL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrSysAllocStringW(szValue, pbstr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT HrSHGetValue(IN HKEY hKey, IN LPCTSTR pszSubKey, OPTIONAL IN LPCTSTR pszValue, OPTIONAL OUT LPDWORD pdwType,
|
|
OPTIONAL OUT LPVOID pvData, OPTIONAL OUT LPDWORD pcbData)
|
|
{
|
|
DWORD dwError = SHGetValue(hKey, pszSubKey, pszValue, pdwType, pvData, pcbData);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrSHSetValue(IN HKEY hkey, IN LPCTSTR pszSubKey, OPTIONAL IN LPCTSTR pszValue, DWORD dwType, OPTIONAL OUT LPVOID pvData, IN DWORD cbData)
|
|
{
|
|
DWORD dwError = SHSetValue(hkey, pszSubKey, pszValue, dwType, pvData, cbData);
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
HRESULT HrRegSetValueString(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, OUT LPCWSTR pszString)
|
|
{
|
|
DWORD cbSize = ((lstrlenW(pszString) + 1) * sizeof(pszString[0]));
|
|
|
|
return HrSHSetValue(hKey, pszSubKey, pszValueName, REG_SZ, (BYTE *)pszString, cbSize);
|
|
}
|
|
|
|
|
|
HRESULT HrRegGetValueString(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, IN LPWSTR pszString, IN DWORD cchSize)
|
|
{
|
|
DWORD dwType;
|
|
DWORD cbSize = (cchSize * sizeof(pszString[0]));
|
|
|
|
HRESULT hr = HrSHGetValue(hKey, pszSubKey, pszValueName, &dwType, (BYTE *)pszString, &cbSize);
|
|
if (SUCCEEDED(hr) && (REG_SZ != dwType))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
DESCRIPTION:
|
|
This function will store paths in the registry. The user calls the
|
|
fuction with full paths are they are converted to relative path. The
|
|
strings prefer to be stored in REG_EXPAND_SZ, but it will fallback to
|
|
REG_SZ if needed.
|
|
\*****************************************************************************/
|
|
HRESULT HrRegSetPath(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, BOOL fUseExpandSZ, OUT LPCWSTR pszPath)
|
|
{
|
|
TCHAR szFinalPath[MAX_PATH];
|
|
|
|
if (!PathUnExpandEnvStrings(pszPath, szFinalPath, ARRAYSIZE(szFinalPath)))
|
|
{
|
|
StringCchCopy(szFinalPath, ARRAYSIZE(szFinalPath), pszPath); // We failed so use the original.
|
|
}
|
|
|
|
DWORD cbSize = ((lstrlenW(szFinalPath) + 1) * sizeof(szFinalPath[0]));
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (fUseExpandSZ)
|
|
{
|
|
hr = HrSHSetValue(hKey, pszSubKey, pszValueName, REG_EXPAND_SZ, (BYTE *)szFinalPath, cbSize);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Maybe it already exists as a REG_SZ so we will store it there. Note that we are still storing it
|
|
// unexpanded even thought it's in REG_SZ. If the caller does not like it, use
|
|
// another function like SHRegSetPath().
|
|
cbSize = ((lstrlenW(szFinalPath) + 1) * sizeof(szFinalPath[0]));
|
|
hr = HrSHSetValue(hKey, pszSubKey, pszValueName, REG_SZ, (BYTE *)szFinalPath, cbSize);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT HrRegGetPath(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, IN LPWSTR pszPath, IN DWORD cchSize)
|
|
{
|
|
TCHAR szFinalPath[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD cbSize = sizeof(szFinalPath);
|
|
|
|
HRESULT hr = HrSHGetValue(hKey, pszSubKey, pszValueName, &dwType, (BYTE *)szFinalPath, &cbSize);
|
|
if (SUCCEEDED(hr) &&
|
|
((REG_EXPAND_SZ == dwType) || (REG_SZ == dwType)))
|
|
{
|
|
if (0 == SHExpandEnvironmentStrings(szFinalPath, pszPath, cchSize))
|
|
{
|
|
StringCchCopy(pszPath, cchSize, szFinalPath); // We failed so use the original.
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT HrRegDeleteValue(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HKEY hKeySub = hKey;
|
|
|
|
if (pszSubKey)
|
|
{
|
|
hr = HrRegOpenKeyEx(hKey, pszSubKey, 0, KEY_WRITE, &hKeySub);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwError = RegDeleteValue(hKeySub, pszValueName);
|
|
|
|
hr = ResultFromWin32(dwError);
|
|
}
|
|
|
|
if (hKeySub == hKey)
|
|
{
|
|
RegCloseKey(hKeySub);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
DWORD HrRegGetDWORD(HKEY hKey, LPCWSTR szKey, LPCWSTR szValue, DWORD dwDefault)
|
|
{
|
|
DWORD dwResult = dwDefault;
|
|
DWORD cbSize = sizeof(dwResult);
|
|
DWORD dwType;
|
|
DWORD dwError = SHGetValue(hKey, szKey, szValue, &dwType, &dwResult, &cbSize);
|
|
|
|
if ((ERROR_SUCCESS != dwError) ||
|
|
((REG_DWORD != dwType) && (REG_BINARY != dwType)) || (sizeof(dwResult) != cbSize))
|
|
{
|
|
return dwDefault;
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
HRESULT HrRegSetDWORD(HKEY hKey, LPCWSTR szKey, LPCWSTR szValue, DWORD dwData)
|
|
{
|
|
DWORD dwError = SHSetValue(hKey, szKey, szValue, REG_DWORD, &dwData, sizeof(dwData));
|
|
|
|
return ResultFromWin32(dwError);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Palette Helpers
|
|
/////////////////////////////////////////////////////////////////////
|
|
COLORREF GetNearestPaletteColor(HPALETTE hpal, COLORREF rgb)
|
|
{
|
|
PALETTEENTRY pe = {0};
|
|
UINT nIndex = GetNearestPaletteIndex(hpal, rgb & 0x00FFFFFF);
|
|
|
|
if (CLR_INVALID != nIndex)
|
|
{
|
|
GetPaletteEntries(hpal, nIndex, 1, &pe);
|
|
}
|
|
|
|
return RGB(pe.peRed, pe.peGreen, pe.peBlue);
|
|
}
|
|
|
|
|
|
BOOL IsPaletteColor(HPALETTE hpal, COLORREF rgb)
|
|
{
|
|
return GetNearestPaletteColor(hpal, rgb) == (rgb & 0xFFFFFF);
|
|
}
|
|
|
|
|
|
|
|
BOOL _InitComCtl32()
|
|
{
|
|
static BOOL fInitialized = FALSE;
|
|
|
|
if (!fInitialized)
|
|
{
|
|
INITCOMMONCONTROLSEX icc;
|
|
|
|
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
icc.dwICC = (ICC_ANIMATE_CLASS | ICC_USEREX_CLASSES | ICC_COOL_CLASSES | ICC_INTERNET_CLASSES | ICC_PAGESCROLLER_CLASS | ICC_NATIVEFNTCTL_CLASS | ICC_LISTVIEW_CLASSES | ICC_LINK_CLASS);
|
|
fInitialized = InitCommonControlsEx(&icc);
|
|
}
|
|
return fInitialized;
|
|
}
|
|
|
|
|
|
DWORD GetCurrentSessionID(void)
|
|
{
|
|
DWORD dwProcessID = (DWORD) -1;
|
|
ProcessIdToSessionId(GetCurrentProcessId(), &dwProcessID);
|
|
|
|
return dwProcessID;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
LPCWSTR pszRegKey;
|
|
LPCWSTR pszRegValue;
|
|
} TSPERFFLAG_ITEM;
|
|
|
|
const TSPERFFLAG_ITEM s_TSPerfFlagItems[] =
|
|
{
|
|
{L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Remote\\%d", L"ActiveDesktop"}, // TSPerFlag_NoADWallpaper
|
|
{L"Remote\\%d\\Control Panel\\Desktop", L"Wallpaper"}, // TSPerFlag_NoWallpaper
|
|
{L"Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager\\Remote\\%d", L"ThemeActive"}, // TSPerFlag_NoVisualStyles
|
|
{L"Remote\\%d\\Control Panel\\Desktop", L"DragFullWindows"}, // TSPerFlag_NoWindowDrag
|
|
{L"Remote\\%d\\Control Panel\\Desktop", L"SmoothScroll"}, // TSPerFlag_NoAnimation
|
|
};
|
|
|
|
|
|
BOOL IsTSPerfFlagEnabled(enumTSPerfFlag eTSFlag)
|
|
{
|
|
BOOL fIsTSFlagEnabled = FALSE;
|
|
static BOOL s_fTSSession = -10;
|
|
|
|
if (-10 == s_fTSSession)
|
|
{
|
|
s_fTSSession = GetSystemMetrics(SM_REMOTESESSION);
|
|
}
|
|
|
|
if (s_fTSSession)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD cbSize = sizeof(szTemp);
|
|
TCHAR szRegKey[MAX_PATH];
|
|
|
|
StringCchPrintf(szRegKey, ARRAYSIZE(szRegKey), s_TSPerfFlagItems[eTSFlag].pszRegKey, GetCurrentSessionID());
|
|
|
|
if (ERROR_SUCCESS == SHGetValueW(HKEY_CURRENT_USER, szRegKey, s_TSPerfFlagItems[eTSFlag].pszRegValue, &dwType, (void *)szTemp, &cbSize))
|
|
{
|
|
fIsTSFlagEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
return fIsTSFlagEnabled;
|
|
}
|
|
|
|
|
|
HRESULT HrShellExecute(HWND hwnd, LPCTSTR lpVerb, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HINSTANCE hReturn = ShellExecute(hwnd, lpVerb, lpFile, lpParameters, lpDirectory, nShowCmd);
|
|
|
|
if ((HINSTANCE)32 > hReturn)
|
|
{
|
|
hr = ResultFromLastError();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT StrReplaceToken(IN LPCTSTR pszToken, IN LPCTSTR pszReplaceValue, IN LPTSTR pszString, IN DWORD cchSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPTSTR pszTempLastHalf = NULL;
|
|
LPTSTR pszNextToken = pszString;
|
|
|
|
while (0 != (pszNextToken = StrStrI(pszNextToken, pszToken)))
|
|
{
|
|
// We found one.
|
|
LPTSTR pszPastToken = pszNextToken + lstrlen(pszToken);
|
|
|
|
Str_SetPtr(&pszTempLastHalf, pszPastToken); // Keep a copy because we will overwrite it.
|
|
|
|
pszNextToken[0] = 0; // Remove the rest of the string.
|
|
StringCchCat(pszString, cchSize, pszReplaceValue);
|
|
StringCchCat(pszString, cchSize, pszTempLastHalf);
|
|
|
|
pszNextToken += lstrlen(pszReplaceValue);
|
|
}
|
|
|
|
Str_SetPtr(&pszTempLastHalf, NULL);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT HrWritePrivateProfileStringW(LPCWSTR pszAppName, LPCWSTR pszKeyName, LPCWSTR pszString, LPCWSTR pszFileName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!WritePrivateProfileStringW(pszAppName, pszKeyName, pszString, pszFileName))
|
|
{
|
|
hr = ResultFromLastError();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL IUnknown_CompareCLSID(IN IUnknown * punk, IN CLSID clsid)
|
|
{
|
|
BOOL fIsEqual = FALSE;
|
|
|
|
if (punk)
|
|
{
|
|
CLSID clsidPageID;
|
|
HRESULT hr = IUnknown_GetClassID(punk, &clsidPageID);
|
|
|
|
if (SUCCEEDED(hr) && IsEqualCLSID(clsidPageID, clsid))
|
|
{
|
|
fIsEqual = TRUE;
|
|
}
|
|
}
|
|
|
|
return fIsEqual;
|
|
}
|
|
|
|
|
|
HRESULT IEnumUnknown_FindCLSID(IN IUnknown * punk, IN CLSID clsid, OUT IUnknown ** ppunkFound)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (punk && ppunkFound)
|
|
{
|
|
IEnumUnknown * pEnum;
|
|
|
|
*ppunkFound = NULL;
|
|
hr = punk->QueryInterface(IID_PPV_ARG(IEnumUnknown, &pEnum));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IUnknown * punkToTry;
|
|
ULONG ulFetched;
|
|
|
|
pEnum->Reset();
|
|
|
|
hr = E_FAIL;
|
|
while (SUCCEEDED(pEnum->Next(1, &punkToTry, &ulFetched)) &&
|
|
(1 == ulFetched))
|
|
{
|
|
if (IUnknown_CompareCLSID(punkToTry, clsid))
|
|
{
|
|
*ppunkFound = punkToTry;
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
punkToTry->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BYTE WINAPI MyStrToByte(LPCTSTR sz)
|
|
{
|
|
BYTE l=0;
|
|
|
|
while (*sz >= TEXT('0') && *sz <= TEXT('9'))
|
|
{
|
|
l = (BYTE) l*10 + (*sz++ - TEXT('0'));
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
|
|
COLORREF ConvertColor(LPTSTR pszColor)
|
|
{
|
|
BYTE RGBTemp[3];
|
|
LPTSTR pszTemp = pszColor;
|
|
UINT i;
|
|
|
|
if (!pszColor || !*pszColor)
|
|
{
|
|
return RGB(0,0,0);
|
|
}
|
|
|
|
for (i =0; i < 3; i++)
|
|
{
|
|
// Remove leading spaces
|
|
while (*pszTemp == TEXT(' '))
|
|
{
|
|
pszTemp++;
|
|
}
|
|
|
|
// Set pszColor to the beginning of the number
|
|
pszColor = pszTemp;
|
|
|
|
// Find the end of the number and null terminate
|
|
while ((*pszTemp) && (*pszTemp != TEXT(' ')))
|
|
{
|
|
pszTemp++;
|
|
}
|
|
|
|
if (*pszTemp != TEXT('\0'))
|
|
{
|
|
*pszTemp = TEXT('\0');
|
|
}
|
|
|
|
pszTemp++;
|
|
RGBTemp[i] = MyStrToByte(pszColor);
|
|
}
|
|
|
|
return (RGB(RGBTemp[0], RGBTemp[1], RGBTemp[2]));
|
|
}
|
|
|
|
|
|
|
|
// Paremeters:
|
|
// hwndOwner -- owner window
|
|
// idTemplate -- specifies template (e.g., "Can't open %2%s\n\n%1%s")
|
|
// hr -- specifies the HRESULT error code
|
|
// pszParam -- specifies the 2nd parameter to idTemplate
|
|
// dwFlags -- flags for MessageBox
|
|
UINT ErrorMessageBox(HWND hwndOwner, LPCTSTR pszTitle, UINT idTemplate, HRESULT hr, LPCTSTR pszParam, UINT dwFlags)
|
|
{
|
|
TCHAR szErrNumString[MAX_PATH * 2];
|
|
TCHAR szTemplate[MAX_PATH * 2];
|
|
TCHAR szErrMsg[MAX_PATH * 2];
|
|
|
|
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr, 0, szErrNumString, ARRAYSIZE(szErrNumString), NULL))
|
|
{
|
|
szErrNumString[0] = 0; // We will not be able to display an error message.
|
|
}
|
|
|
|
// These error messages are so useless to customers, that we prefer to leave it blank.
|
|
if ((E_INVALIDARG == hr) ||
|
|
(ResultFromWin32(ERROR_INVALID_PARAMETER) == hr))
|
|
{
|
|
szErrNumString[0] = 0;
|
|
}
|
|
|
|
LoadString(HINST_THISDLL, idTemplate, szTemplate, ARRAYSIZE(szTemplate));
|
|
if (pszParam)
|
|
{
|
|
StringCchPrintf(szErrMsg, ARRAYSIZE(szErrMsg), szTemplate, szErrNumString, pszParam);
|
|
}
|
|
else
|
|
{
|
|
StringCchPrintf(szErrMsg, ARRAYSIZE(szErrMsg), szTemplate, szErrNumString);
|
|
}
|
|
|
|
return MessageBox(hwndOwner, szErrMsg, pszTitle, (MB_OK | MB_ICONERROR));
|
|
}
|
|
|
|
|
|
HRESULT DisplayThemeErrorDialog(HWND hwndParent, HRESULT hrError, UINT nTitle, UINT nTemplate)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (FAILED(hrError))
|
|
{
|
|
hr = ResultFromWin32(ERROR_CANCELLED);
|
|
if (!g_fInSetup && // Don't display an error during setup.
|
|
(ResultFromWin32(ERROR_CANCELLED) != hrError))
|
|
{
|
|
//---- get error from theme manager ----
|
|
WCHAR szErrorMsg[MAX_PATH*2];
|
|
WCHAR szTitle[MAX_PATH];
|
|
|
|
szErrorMsg[0] = 0; // In case the error function fails.
|
|
if (FAILED(hrError))
|
|
{
|
|
PARSE_ERROR_INFO Info = {sizeof(Info)};
|
|
|
|
if (SUCCEEDED(GetThemeParseErrorInfo(&Info)))
|
|
{
|
|
StringCchCopy(szErrorMsg, ARRAYSIZE(szErrorMsg), Info.szMsg);
|
|
}
|
|
else
|
|
{
|
|
*szErrorMsg = 0; // no error avail
|
|
}
|
|
}
|
|
|
|
// We want to display UI if an error occured here. We want to do
|
|
// it instead of our parent because THEMELOADPARAMS contains
|
|
// extra error information that we can't pass back to the caller.
|
|
// However, we will only display error UI if our caller wants us
|
|
// to. We determine that by the fact that they make an hwnd available
|
|
// to us. We get the hwnd by getting our site pointer and getting
|
|
// the hwnd via ::GetWindow().
|
|
LoadString(HINST_THISDLL, nTitle, szTitle, ARRAYSIZE(szTitle));
|
|
ErrorMessageBox(hwndParent, szTitle, nTemplate, hrError, szErrorMsg, (MB_OK | MB_ICONEXCLAMATION));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
extern BOOL FadeEffectAvailable(void);
|
|
|
|
void LogStartInformation(void)
|
|
{
|
|
BOOL fTemp;
|
|
|
|
// Frequently users will report that something is broken in the Display CPL.
|
|
// However, the real problem is that someone turned on a policy that locks UI
|
|
// and the user didn't know that the policy was enabled. We log those here so
|
|
// it's quick to find those issues.
|
|
if (SHRestricted(REST_NODISPLAYCPL)) LogStatus("POLICY ENABLED: Do not show the Display CPL.");
|
|
if (SHRestricted(REST_NODISPLAYAPPEARANCEPAGE)) LogStatus("POLICY ENABLED: Hide the Themes and Appearance tab.");
|
|
if (SHRestricted(REST_NOTHEMESTAB)) LogStatus("POLICY ENABLED: Hide the Themes tab.");
|
|
if (SHRestricted(REST_NODISPBACKGROUND)) LogStatus("POLICY ENABLED: Hide the Desktop tab.");
|
|
if (SHRestricted(REST_NODISPSCREENSAVEPG)) LogStatus("POLICY ENABLED: Hide the ScreenSaver tab.");
|
|
if (SHRestricted(REST_NODISPSETTINGSPG)) LogStatus("POLICY ENABLED: Hide the Settings tab.");
|
|
if (SHRestricted(REST_NOVISUALSTYLECHOICE)) LogStatus("POLICY ENABLED: User not allowed to change the Visual Style.");
|
|
if (SHRestricted(REST_NOCOLORCHOICE)) LogStatus("POLICY ENABLED: User Not allowed to change the Visual Style Color Selection.");
|
|
if (SHRestricted(REST_NOSIZECHOICE)) LogStatus("POLICY ENABLED: User not allowed to change the Visual Style size selection.");
|
|
|
|
if (0 != SHGetRestriction(NULL,POLICY_KEY_EXPLORER,POLICY_VALUE_ANIMATION)) LogStatus("POLICY ENABLED: Policy disallows fade effect. (Effects dialog)");
|
|
if (0 != SHGetRestriction(NULL,POLICY_KEY_EXPLORER, POLICY_VALUE_KEYBOARDNAV)) LogStatus("POLICY ENABLED: Policy disallows changing underline key accell. (Effects dialog)");
|
|
if (0 != SHGetRestriction(NULL,POLICY_KEY_ACTIVEDESKTOP, SZ_POLICY_NOCHANGEWALLPAPER)) LogStatus("POLICY ENABLED: Policy disallows changing wallpaper. (Desktop tab)");
|
|
if (0 != SHGetRestriction(NULL,POLICY_KEY_SYSTEM, SZ_POLICY_NODISPSCREENSAVERPG)) LogStatus("POLICY ENABLED: Policy hides ScreenSaver page.");
|
|
if (0 != SHGetRestriction(SZ_REGKEY_POLICIES_DESKTOP, NULL, SZ_POLICY_SCREENSAVEACTIVE)) LogStatus("POLICY ENABLED: Policy forces screensaver on or off");
|
|
if (0 != SHGetRestriction(NULL,POLICY_KEY_EXPLORER, POLICY_VALUE_KEYBOARDNAV)) LogStatus("POLICY ENABLED: Policy disallows changing underline key accell. (Effects dialog)");
|
|
|
|
if (IsTSPerfFlagEnabled(TSPerFlag_NoAnimation)) LogStatus("POLICY ENABLED: TS Perf Policy disallows animations. (Effects dialog)");
|
|
if (IsTSPerfFlagEnabled(TSPerFlag_NoWindowDrag)) LogStatus("POLICY ENABLED: TS Perf Policy disallows full window drag. (Effects dialog)");
|
|
if (IsTSPerfFlagEnabled(TSPerFlag_NoVisualStyles)) LogStatus("POLICY ENABLED: TS Perf Policy disallows visual styles.");
|
|
if (IsTSPerfFlagEnabled(TSPerFlag_NoWallpaper)) LogStatus("POLICY ENABLED: TS Perf Policy disallows Wallpaper.");
|
|
if (IsTSPerfFlagEnabled(TSPerFlag_NoADWallpaper)) LogStatus("POLICY ENABLED: TS Perf Policy disallows AD Wallpaper.");
|
|
|
|
if (!FadeEffectAvailable()) LogStatus("POLICY ENABLED: A policy forces Fade Effects off (Effects dialog)");
|
|
|
|
if (!ClassicSystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, (PVOID)&fTemp, 0)) LogStatus("POLICY ENABLED: SPI_GETFONTSMOOTHINGTYPE hides FontSmoothing. (Effects dialog)");
|
|
if (ClassicSystemParametersInfo(SPI_GETUIEFFECTS, 0, (PVOID) &fTemp, 0) && !fTemp) LogStatus("POLICY ENABLED: SPI_GETUIEFFECTS hides lots of UI effects. (Effects dialog)");
|
|
if (ClassicSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (PVOID) &fTemp, 0) && !fTemp) LogStatus("POLICY ENABLED: SPI_GETGRADIENTCAPTIONS turns off Caption bar Gradients. (Advance Appearance)");
|
|
}
|
|
|
|
|
|
void LogStatus(LPCSTR pszMessage, ...)
|
|
{
|
|
static int nLogOn = -1;
|
|
va_list vaParamList;
|
|
|
|
va_start(vaParamList, pszMessage);
|
|
|
|
if (-1 == nLogOn)
|
|
{
|
|
nLogOn = (SHRegGetBoolUSValue(SZ_THEMES, SZ_REGVALUE_LOGINFO, FALSE, FALSE) ? 1 : 0);
|
|
}
|
|
|
|
if (1 == nLogOn)
|
|
{
|
|
if (INVALID_HANDLE_VALUE == g_hLogFile)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
if (GetWindowsDirectory(szPath, ARRAYSIZE(szPath)))
|
|
{
|
|
if (PathAppend(szPath, TEXT("Theme.log")))
|
|
{
|
|
g_hLogFile = CreateFile(szPath, (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE != g_hLogFile)
|
|
{
|
|
WCHAR szUserName[MAX_PATH];
|
|
CHAR szTimeDate[MAX_PATH];
|
|
CHAR szHeader[MAX_PATH];
|
|
FILETIME ftCurrentUTC;
|
|
FILETIME ftCurrent;
|
|
SYSTEMTIME stCurrent;
|
|
DWORD cbWritten;
|
|
|
|
SetFilePointer(g_hLogFile, 0, NULL, FILE_END);
|
|
|
|
GetLocalTime(&stCurrent);
|
|
SystemTimeToFileTime(&stCurrent, &ftCurrent);
|
|
LocalFileTimeToFileTime(&ftCurrent, &ftCurrentUTC);
|
|
SHFormatDateTimeA(&ftCurrentUTC, NULL, szTimeDate, ARRAYSIZE(szTimeDate));
|
|
|
|
ULONG cchUserSize = ARRAYSIZE(szUserName);
|
|
if (!GetUserNameEx(NameDisplay, szUserName, &cchUserSize) &&
|
|
!GetUserNameEx(NameUserPrincipal, szUserName, &cchUserSize) &&
|
|
!GetUserNameEx(NameSamCompatible, szUserName, &cchUserSize) &&
|
|
!GetUserNameEx(NameUniqueId, szUserName, &cchUserSize))
|
|
{
|
|
szUserName[0] = 0;
|
|
}
|
|
|
|
TCHAR szProcess[MAX_PATH];
|
|
if (!GetModuleFileName(NULL, szProcess, ARRAYSIZE(szProcess)))
|
|
{
|
|
szProcess[0] = 0;
|
|
}
|
|
|
|
StringCchPrintfA(szHeader, ARRAYSIZE(szHeader), "\r\n\r\n%hs - USER: %ls (%ls)\r\n", szTimeDate, szUserName, szProcess);
|
|
WriteFile(g_hLogFile, szHeader, lstrlenA(szHeader), &cbWritten, NULL);
|
|
|
|
// Log information that we need to do on every startup. (Like Policies that are on that confuse people)
|
|
LogStartInformation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (INVALID_HANDLE_VALUE != g_hLogFile)
|
|
{
|
|
CHAR szMessage[4000];
|
|
DWORD cbWritten;
|
|
StringCchVPrintfA(szMessage, ARRAYSIZE(szMessage), pszMessage, vaParamList);
|
|
WriteFile(g_hLogFile, szMessage, lstrlenA(szMessage), &cbWritten, NULL);
|
|
}
|
|
}
|
|
|
|
va_end(vaParamList);
|
|
}
|
|
|
|
|
|
void LogSystemMetrics(LPCSTR pszMessage, SYSTEMMETRICSALL * pSystemMetrics)
|
|
{
|
|
CHAR szSysMetrics[1024]; // Random because it's big.
|
|
|
|
if (pSystemMetrics)
|
|
{
|
|
StringCchPrintfA(szSysMetrics, ARRAYSIZE(szSysMetrics), "Sz(Brdr=%d, Scrl=%d, Cap=%d, Menu=%d, Icon=%d, DXIn=%d) Ft(Cap=%d(%d), SmCap=%d(%d), Menu=%d(%d), Stus=%d(%d), Msg=%d(%d))",
|
|
pSystemMetrics->schemeData.ncm.iBorderWidth,
|
|
pSystemMetrics->schemeData.ncm.iScrollWidth,
|
|
pSystemMetrics->schemeData.ncm.iCaptionHeight,
|
|
pSystemMetrics->schemeData.ncm.iMenuHeight,
|
|
pSystemMetrics->nIcon,
|
|
pSystemMetrics->nDYIcon,
|
|
pSystemMetrics->schemeData.ncm.lfCaptionFont.lfHeight,
|
|
pSystemMetrics->schemeData.ncm.lfCaptionFont.lfCharSet,
|
|
pSystemMetrics->schemeData.ncm.lfSmCaptionFont.lfHeight,
|
|
pSystemMetrics->schemeData.ncm.lfSmCaptionFont.lfCharSet,
|
|
pSystemMetrics->schemeData.ncm.lfMenuFont.lfHeight,
|
|
pSystemMetrics->schemeData.ncm.lfMenuFont.lfCharSet,
|
|
pSystemMetrics->schemeData.ncm.lfStatusFont.lfHeight,
|
|
pSystemMetrics->schemeData.ncm.lfStatusFont.lfCharSet,
|
|
pSystemMetrics->schemeData.ncm.lfMessageFont.lfHeight,
|
|
pSystemMetrics->schemeData.ncm.lfMessageFont.lfCharSet);
|
|
}
|
|
else
|
|
{
|
|
szSysMetrics[0] = 0;
|
|
}
|
|
|
|
LogStatus("SYSMET: %s: %s\r\n", pszMessage, szSysMetrics);
|
|
}
|
|
|
|
|
|
|
|
HRESULT SHGetResourcePath(BOOL fLocaleNode, IN LPWSTR pszPath, IN DWORD cchSize)
|
|
{
|
|
DWORD dwFlags = (CSIDL_FLAG_CREATE | CSIDL_RESOURCES);
|
|
|
|
return SHGetFolderPath(NULL, dwFlags, NULL, 0, pszPath);
|
|
}
|
|
|
|
|
|
#define SZ_RESOURCEDIR_TOKEN TEXT("%ResourceDir%")
|
|
#define SZ_RESOURCELDIR_TOKEN TEXT("%ResourceDirL%")
|
|
HRESULT ExpandResourceDir(IN LPWSTR pszPath, IN DWORD cchSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fLocalized = FALSE;
|
|
LPCTSTR pszToken = StrStrW(pszPath, SZ_RESOURCEDIR_TOKEN);
|
|
|
|
if (!pszToken)
|
|
{
|
|
pszToken = StrStrW(pszPath, SZ_RESOURCELDIR_TOKEN);
|
|
}
|
|
|
|
// Do we have stuff to replace?
|
|
if (pszToken)
|
|
{
|
|
// Yes, so get the replacement value.
|
|
WCHAR szResourceDir[MAX_PATH];
|
|
|
|
hr = SHGetResourcePath(fLocalized, szResourceDir, ARRAYSIZE(szResourceDir));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StrReplaceToken((fLocalized ? SZ_RESOURCELDIR_TOKEN : SZ_RESOURCEDIR_TOKEN), szResourceDir, pszPath, cchSize);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDAPI SHPropertyBag_WritePunk(IN IPropertyBag * pPropertyPage, IN LPCWSTR pwzPropName, IN IUnknown * punk)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pPropertyPage && pwzPropName)
|
|
{
|
|
VARIANT va;
|
|
|
|
va.vt = VT_UNKNOWN;
|
|
va.punkVal = punk;
|
|
|
|
hr = pPropertyPage->Write(pwzPropName, &va);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDAPI SHPropertyBag_ReadByRef(IN IPropertyBag * pPropertyPage, IN LPCWSTR pwzPropName, IN void * p, IN SIZE_T cbSize)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pPropertyPage && pwzPropName && p)
|
|
{
|
|
VARIANT va;
|
|
|
|
hr = pPropertyPage->Read(pwzPropName, &va, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((VT_BYREF == va.vt) && va.byref)
|
|
{
|
|
CopyMemory(p, va.byref, cbSize);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDAPI SHPropertyBag_WriteByRef(IN IPropertyBag * pPropertyPage, IN LPCWSTR pwzPropName, IN void * p)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pPropertyPage && pwzPropName && p)
|
|
{
|
|
VARIANT va;
|
|
|
|
va.vt = VT_BYREF;
|
|
va.byref = p;
|
|
hr = pPropertyPage->Write(pwzPropName, &va);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
LONG s_cSpiDummy = -1;
|
|
LONG *g_pcSpiThreads = &s_cSpiDummy;
|
|
|
|
void SPISetThreadCounter(LONG *pcThreads)
|
|
{
|
|
if (!pcThreads)
|
|
pcThreads = &s_cSpiDummy;
|
|
InterlockedExchangePointer((void **) &g_pcSpiThreads, pcThreads);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
LPTHREAD_START_ROUTINE pfnThreadProc;
|
|
void *pvData;
|
|
UINT idThread;
|
|
}SPITHREAD;
|
|
|
|
DWORD CALLBACK _SPIWrapperThreadProc(void *pv)
|
|
{
|
|
SPITHREAD *pspi = (SPITHREAD *)pv;
|
|
DWORD dwRet = pspi->pfnThreadProc(pspi->pvData);
|
|
// then we check to see
|
|
ASSERT( 0 != *g_pcSpiThreads );
|
|
if (0 == InterlockedDecrement(g_pcSpiThreads))
|
|
{
|
|
PostThreadMessage(pspi->idThread, WM_NULL, 0, 0);
|
|
}
|
|
delete pspi;
|
|
return dwRet;
|
|
}
|
|
|
|
BOOL SPICreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, void *pvData)
|
|
{
|
|
SPITHREAD *pspi = new SPITHREAD;
|
|
if (pspi)
|
|
{
|
|
pspi->idThread = GetCurrentThreadId();
|
|
pspi->pfnThreadProc = pfnThreadProc;
|
|
pspi->pvData = pvData;
|
|
InterlockedIncrement(g_pcSpiThreads);
|
|
return SHCreateThread(_SPIWrapperThreadProc, pspi, (CTF_COINIT | CTF_INSIST | CTF_FREELIBANDEXIT), NULL);
|
|
}
|
|
else
|
|
{
|
|
// CTF_INSIST
|
|
pfnThreadProc(pvData);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
void PostMessageBroadAsync(IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam)
|
|
{
|
|
// We don't want to hang our UI if other apps are hung or slow when
|
|
// we need to tell them to update their changes. So we choose this
|
|
// mechanism.
|
|
//
|
|
// The alternatives are:
|
|
// SendMessageCallback: Except we don't need to do anything when the apps
|
|
// are done.
|
|
// SendMessageTimeout: Except we don't want to incure any timeout.
|
|
PostMessage(HWND_BROADCAST, Msg, wParam, lParam);
|
|
}
|
|
|
|
|
|
typedef struct
|
|
{
|
|
BOOL fFree; // Do you need to call LocalFree() on pvData?
|
|
UINT uiAction;
|
|
UINT uiParam;
|
|
UINT fWinIni;
|
|
void * pvData;
|
|
CDimmedWindow* pDimmedWindow;
|
|
} SPIS_INFO;
|
|
|
|
DWORD SystemParametersInfoAsync_WorkerThread(IN void *pv)
|
|
{
|
|
SPIS_INFO * pSpisInfo = (SPIS_INFO *) pv;
|
|
HINSTANCE hInstance = LoadLibrary(TEXT("desk.cpl"));
|
|
|
|
if (pSpisInfo)
|
|
{
|
|
ClassicSystemParametersInfo(pSpisInfo->uiAction, pSpisInfo->uiParam, pSpisInfo->pvData, pSpisInfo->fWinIni);
|
|
if (pSpisInfo->fFree && pSpisInfo->pvData)
|
|
{
|
|
LocalFree(pSpisInfo->pvData);
|
|
}
|
|
|
|
if (pSpisInfo->pDimmedWindow)
|
|
{
|
|
pSpisInfo->pDimmedWindow->Release();
|
|
}
|
|
|
|
LocalFree(pv);
|
|
}
|
|
|
|
if (hInstance)
|
|
{
|
|
FreeLibrary(hInstance);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void SystemParametersInfoAsync(IN UINT uiAction, IN UINT uiParam, IN void * pvParam, IN DWORD cbSize, IN UINT fWinIni, IN CDimmedWindow* pDimmedWindow)
|
|
{
|
|
// ClassicSystemParametersInfo() will hang if a top level window is hung (#162570) and USER will not fix that bug.
|
|
// Therefore, we need to make that API call on a background thread because we need to
|
|
// be more rebust than to hang.
|
|
SPIS_INFO * pSpisInfo = (SPIS_INFO *) LocalAlloc(LPTR, sizeof(*pSpisInfo));
|
|
|
|
if (pSpisInfo)
|
|
{
|
|
BOOL fAsyncOK = TRUE;
|
|
|
|
pSpisInfo->fFree = (0 != cbSize);
|
|
pSpisInfo->pvData = pvParam;
|
|
pSpisInfo->uiAction = uiAction;
|
|
pSpisInfo->uiParam = uiParam;
|
|
pSpisInfo->fWinIni = fWinIni;
|
|
pSpisInfo->pDimmedWindow = pDimmedWindow;
|
|
// Spawning thread is responsible for addref dimmed window, but not releasing
|
|
// that is the repsonsibility of the spawned thread
|
|
if (pSpisInfo->pDimmedWindow)
|
|
{
|
|
pSpisInfo->pDimmedWindow->AddRef();
|
|
}
|
|
|
|
if (pSpisInfo->fFree)
|
|
{
|
|
pSpisInfo->pvData = LocalAlloc(LPTR, cbSize);
|
|
if (!pSpisInfo->pvData)
|
|
{
|
|
pSpisInfo->pvData = pvParam;
|
|
fAsyncOK = FALSE;
|
|
pSpisInfo->fFree = FALSE;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(pSpisInfo->pvData, pvParam, cbSize);
|
|
}
|
|
}
|
|
|
|
if (fAsyncOK)
|
|
SPICreateThread(SystemParametersInfoAsync_WorkerThread, (void *)pSpisInfo);
|
|
else
|
|
SystemParametersInfoAsync_WorkerThread((void *)pSpisInfo);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT GetCurrentUserCustomName(LPWSTR pszDisplayName, DWORD cchSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// It failed, so load "My Custom Theme". This may happen on personal.
|
|
LoadString(HINST_THISDLL, IDS_MYCUSTOMTHEME, pszDisplayName, cchSize);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT InstallVisualStyle(IThemeManager * pThemeManager, LPCTSTR pszVisualStylePath, LPCTSTR pszVisualStyleColor, LPCTSTR pszVisualStyleSize)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CComVariant varTheme(pszVisualStylePath);
|
|
|
|
if (varTheme.bstrVal)
|
|
{
|
|
IThemeScheme * pVisualStyle;
|
|
|
|
hr = pThemeManager->get_schemeItem(varTheme, &pVisualStyle);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComVariant varStyleName(pszVisualStyleColor);
|
|
|
|
if (!varStyleName.bstrVal)
|
|
hr = E_OUTOFMEMORY;
|
|
else
|
|
{
|
|
IThemeStyle * pThemeStyle;
|
|
|
|
hr = pVisualStyle->get_item(varStyleName, &pThemeStyle);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComVariant varSizeName(pszVisualStyleSize);
|
|
|
|
if (!varSizeName.bstrVal)
|
|
hr = E_OUTOFMEMORY;
|
|
else
|
|
{
|
|
IThemeSize * pThemeSize;
|
|
|
|
hr = pThemeStyle->get_item(varSizeName, &pThemeSize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pThemeStyle->put_SelectedSize(pThemeSize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pVisualStyle->put_SelectedStyle(pThemeStyle);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pThemeManager->put_SelectedScheme(pVisualStyle);
|
|
}
|
|
}
|
|
|
|
pThemeSize->Release();
|
|
}
|
|
}
|
|
|
|
pThemeStyle->Release();
|
|
}
|
|
}
|
|
|
|
pVisualStyle->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// {B2A7FD52-301F-4348-B93A-638C6DE49229}
|
|
DEFINE_GUID(CLSID_WMPSkinMngr, 0xB2A7FD52, 0x301F, 0x4348, 0xB9, 0x3A, 0x63, 0x8C, 0x6D, 0xE4, 0x92, 0x29);
|
|
|
|
// {076F2FA6-ED30-448B-8CC5-3F3EF3529C7A}
|
|
DEFINE_GUID(IID_IWMPSkinMngr, 0x076F2FA6, 0xED30, 0x448B, 0x8C, 0xC5, 0x3F, 0x3E, 0xF3, 0x52, 0x9C, 0x7A);
|
|
|
|
HRESULT ApplyVisualStyle(LPCTSTR pszVisualStylePath, LPCTSTR pszVisualStyleColor, LPCTSTR pszVisualStyleSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Load the skin
|
|
hr = SetSystemVisualStyle(pszVisualStylePath, pszVisualStyleColor, pszVisualStyleSize, 0);
|
|
LogStatus("SetSystemVisualStyle(%ls. %ls, %ls) returned hr=%#08lx.\r\n", pszVisualStylePath, pszVisualStyleColor, pszVisualStyleSize, hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComBSTR bstrPath(pszVisualStylePath);
|
|
|
|
if (pszVisualStylePath && !bstrPath)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
IWMPSkinMngr * pWMPSkinMngr;
|
|
|
|
// Ignore failures until we are guarenteed they are in setup.
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_WMPSkinMngr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IWMPSkinMngr, &pWMPSkinMngr))))
|
|
{
|
|
pWMPSkinMngr->SetVisualStyle(bstrPath);
|
|
pWMPSkinMngr->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT GetPageByCLSID(IUnknown * punkSite, const GUID * pClsid, IPropertyBag ** ppPropertyBag)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
*ppPropertyBag = NULL;
|
|
if (punkSite)
|
|
{
|
|
IThemeUIPages * pThemeUI;
|
|
|
|
hr = punkSite->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IEnumUnknown * pEnumUnknown;
|
|
|
|
hr = pThemeUI->GetBasePagesEnum(&pEnumUnknown);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IUnknown * punk;
|
|
|
|
// This may not exit due to policy
|
|
hr = IEnumUnknown_FindCLSID(pEnumUnknown, *pClsid, &punk);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, ppPropertyBag));
|
|
punk->Release();
|
|
}
|
|
|
|
pEnumUnknown->Release();
|
|
}
|
|
|
|
pThemeUI->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
DWORD QueryThemeServicesWrap(void)
|
|
{
|
|
DWORD dwResult = QueryThemeServices();
|
|
|
|
if (IsTSPerfFlagEnabled(TSPerFlag_NoVisualStyles))
|
|
{
|
|
dwResult = (dwResult & ~QTS_AVAILABLE); // Remove the QTS_AVAILABLE flag because they are forced of because of TS Perf Flags
|
|
LogStatus("Visual Styles Forced off because of TS Perf Flags\r\n");
|
|
}
|
|
LogStatus("QueryThemeServices() returned %d. In QueryThemeServicesWrap\r\n", dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
void PathUnExpandEnvStringsWrap(LPTSTR pszString, DWORD cchSize)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
StringCchCopy(szTemp, ARRAYSIZE(szTemp), pszString);
|
|
if (!PathUnExpandEnvStrings(szTemp, pszString, cchSize))
|
|
{
|
|
StringCchCopy(pszString, cchSize, szTemp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PathExpandEnvStringsWrap(LPTSTR pszString, DWORD cchSize)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
StringCchCopy(szTemp, ARRAYSIZE(szTemp), pszString);
|
|
if (0 == SHExpandEnvironmentStrings(szTemp, pszString, cchSize))
|
|
{
|
|
StringCchCopy(pszString, cchSize, szTemp);
|
|
}
|
|
}
|
|
|
|
|
|
// PERF: This API is INCREADIBLY slow so be very very careful when you use it.
|
|
BOOL EnumDisplaySettingsExWrap(LPCTSTR lpszDeviceName, DWORD iModeNum, LPDEVMODE lpDevMode, DWORD dwFlags)
|
|
{
|
|
DEBUG_CODE(DebugStartWatch());
|
|
|
|
BOOL fReturn = EnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
|
|
|
|
DEBUG_CODE(TraceMsg(TF_THEMEUI_PERF, "EnumDisplaySettingsEx() took Time=%lums", DebugStopWatch()));
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
void SystemPathAppend(TCHAR *pszPath, TCHAR *pszMore)
|
|
{
|
|
if (!GetSystemDirectory(pszPath, MAX_PATH) || !PathAppend(pszPath, pszMore))
|
|
{
|
|
StringCchCopy(pszPath, MAX_PATH, pszMore);
|
|
}
|
|
}
|